Compare commits
2 Commits
master
...
featute/Ch
Author | SHA1 | Date | |
---|---|---|---|
d7b5b7e3ab | |||
381557459b |
61
Persistence.API/Controllers/ChangeLogController.cs
Normal file
61
Persistence.API/Controllers/ChangeLogController.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Persistence.Database.Model;
|
||||||
|
using Persistence.Models;
|
||||||
|
using Persistence.Repositories;
|
||||||
|
|
||||||
|
namespace Persistence.API.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
public class ChangeLogRotorController : ControllerBase, IChangeLogApi<ProcessMapRotorDto, ChangeLogDto<ProcessMapRotorDto>>
|
||||||
|
{
|
||||||
|
private IChangeLogRepository<ProcessMapRotorDto, ChangeLogDto<ProcessMapRotorDto>> repository;
|
||||||
|
|
||||||
|
public ChangeLogRotorController(IChangeLogRepository<ProcessMapRotorDto, ChangeLogDto<ProcessMapRotorDto>> repository)
|
||||||
|
{
|
||||||
|
this.repository = repository;
|
||||||
|
}
|
||||||
|
public async Task<ActionResult<int>> Add(ProcessMapRotorDto dto, CancellationToken token)
|
||||||
|
{
|
||||||
|
await repository.InsertRange(0, [dto], token);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ActionResult<int>> AddRange(IEnumerable<ProcessMapRotorDto> dtos, CancellationToken token)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ActionResult<int>> Delete(int id, CancellationToken token)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ActionResult<int>> DeleteRange(IEnumerable<int> ids, CancellationToken token)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ActionResult<IEnumerable<ProcessMapRotorDto>>> GetChangeLogCurrent(CancellationToken token)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ActionResult<IEnumerable<ChangeLogDto<ProcessMapRotorDto>>>> GetChangeLogForDate(DateTimeOffset historyMoment, CancellationToken token)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ActionResult<int>> Update(ProcessMapRotorDto dto, CancellationToken token)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ActionResult<int>> UpdateRange(IEnumerable<ProcessMapRotorDto> dtos, CancellationToken token)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
@ -1,53 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Persistence.Models;
|
|
||||||
using Persistence.Repositories;
|
|
||||||
|
|
||||||
namespace Persistence.API.Controllers
|
|
||||||
{
|
|
||||||
[ApiController]
|
|
||||||
[Authorize]
|
|
||||||
[Route("api/[controller]")]
|
|
||||||
public class SetpointController : ControllerBase, ISetpointApi
|
|
||||||
{
|
|
||||||
private readonly ISetpointRepository setpointRepository;
|
|
||||||
|
|
||||||
public SetpointController(ISetpointRepository setpointRepository)
|
|
||||||
{
|
|
||||||
this.setpointRepository = setpointRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("current")]
|
|
||||||
public async Task<ActionResult<IEnumerable<SetpointValueDto>>> GetCurrent([FromQuery] IEnumerable<Guid> setpointKeys, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await setpointRepository.GetCurrent(setpointKeys, token);
|
|
||||||
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("history")]
|
|
||||||
public async Task<ActionResult<IEnumerable<SetpointValueDto>>> GetHistory([FromQuery] IEnumerable<Guid> setpointKeys, [FromQuery] DateTimeOffset historyMoment, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await setpointRepository.GetHistory(setpointKeys, historyMoment, token);
|
|
||||||
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("log")]
|
|
||||||
public async Task<ActionResult<Dictionary<Guid, IEnumerable<SetpointLogDto>>>> GetLog([FromQuery] IEnumerable<Guid> setpointKeys, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await setpointRepository.GetLog(setpointKeys, token);
|
|
||||||
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<ActionResult<int>> Save(Guid setpointKey, object newValue, CancellationToken token)
|
|
||||||
{
|
|
||||||
// ToDo: вычитка idUser
|
|
||||||
await setpointRepository.Save(setpointKey, newValue, 0, token);
|
|
||||||
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +1,8 @@
|
|||||||
using System.Text.Json.Nodes;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using Microsoft.OpenApi.Any;
|
using Microsoft.OpenApi.Any;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
using Persistence.Models.Configurations;
|
using System.Text.Json.Nodes;
|
||||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
|
||||||
|
|
||||||
namespace Persistence.API;
|
namespace Persistence.API;
|
||||||
|
|
||||||
@ -32,164 +30,59 @@ public static class DependencyInjection
|
|||||||
});
|
});
|
||||||
|
|
||||||
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Persistence web api", Version = "v1" });
|
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Persistence web api", Version = "v1" });
|
||||||
|
c.AddSecurityDefinition("Keycloack", 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'",
|
||||||
|
Name = "Authorization",
|
||||||
|
In = ParameterLocation.Header,
|
||||||
|
Type = SecuritySchemeType.OAuth2,
|
||||||
|
Flows = new OpenApiOAuthFlows
|
||||||
|
{
|
||||||
|
Implicit = new OpenApiOAuthFlow
|
||||||
|
{
|
||||||
|
AuthorizationUrl = new Uri(configuration["Authentication:AuthorizationUrl"]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var needUseKeyCloak = configuration.GetSection("NeedUseKeyCloak").Get<bool>();
|
c.AddSecurityRequirement(new OpenApiSecurityRequirement()
|
||||||
if (needUseKeyCloak)
|
{
|
||||||
c.AddKeycloackSecurity(configuration);
|
{
|
||||||
else c.AddDefaultSecurity(configuration);
|
new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Reference = new OpenApiReference
|
||||||
|
{
|
||||||
|
Type = ReferenceType.SecurityScheme,
|
||||||
|
Id = "Keycloack"
|
||||||
|
},
|
||||||
|
Scheme = "Bearer",
|
||||||
|
Name = "Bearer",
|
||||||
|
In = ParameterLocation.Header,
|
||||||
|
},
|
||||||
|
new List<string>()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
//var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
//var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||||
//var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
//var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
||||||
//var includeControllerXmlComment = true;
|
//var includeControllerXmlComment = true;
|
||||||
//options.IncludeXmlComments(xmlPath, includeControllerXmlComment);
|
//c.IncludeXmlComments(xmlPath, includeControllerXmlComment);
|
||||||
//options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "AsbCloudApp.xml"), includeControllerXmlComment);
|
//c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "AsbCloudApp.xml"), includeControllerXmlComment);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Authentication
|
public static void AddJWTAuthentication(this IServiceCollection services, IConfiguration configuration)
|
||||||
public static void AddJWTAuthentication(this IServiceCollection services, IConfiguration configuration)
|
|
||||||
{
|
{
|
||||||
var needUseKeyCloak = configuration
|
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||||
.GetSection("NeedUseKeyCloak")
|
.AddJwtBearer(o =>
|
||||||
.Get<bool>();
|
{
|
||||||
if (needUseKeyCloak)
|
o.RequireHttpsMetadata = false;
|
||||||
services.AddKeyCloakAuthentication(configuration);
|
o.Audience = configuration["Authentication:Audience"];
|
||||||
else services.AddDefaultAuthentication(configuration);
|
o.MetadataAddress = configuration["Authentication:MetadataAddress"]!;
|
||||||
}
|
o.TokenValidationParameters = new TokenValidationParameters
|
||||||
|
{
|
||||||
private static void AddKeyCloakAuthentication(this IServiceCollection services, IConfiguration configuration)
|
ValidIssuer = configuration["Authentication:ValidIssuer"],
|
||||||
{
|
};
|
||||||
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
});
|
||||||
.AddJwtBearer(options =>
|
}
|
||||||
{
|
|
||||||
options.RequireHttpsMetadata = false;
|
|
||||||
options.Audience = configuration["Authentication:Audience"];
|
|
||||||
options.MetadataAddress = configuration["Authentication:MetadataAddress"]!;
|
|
||||||
options.TokenValidationParameters = new TokenValidationParameters
|
|
||||||
{
|
|
||||||
ValidIssuer = configuration["Authentication:ValidIssuer"],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void AddDefaultAuthentication(this IServiceCollection services, IConfiguration configuration)
|
|
||||||
{
|
|
||||||
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
|
||||||
.AddJwtBearer(options =>
|
|
||||||
{
|
|
||||||
options.RequireHttpsMetadata = false;
|
|
||||||
options.TokenValidationParameters = new TokenValidationParameters
|
|
||||||
{
|
|
||||||
ValidateIssuer = true,
|
|
||||||
ValidIssuer = JwtParams.Issuer,
|
|
||||||
ValidateAudience = true,
|
|
||||||
ValidAudience = JwtParams.Audience,
|
|
||||||
ValidateLifetime = true,
|
|
||||||
IssuerSigningKey = JwtParams.SecurityKey,
|
|
||||||
ValidateIssuerSigningKey = false
|
|
||||||
};
|
|
||||||
options.Events = new JwtBearerEvents
|
|
||||||
{
|
|
||||||
OnMessageReceived = context =>
|
|
||||||
{
|
|
||||||
var accessToken = context.Request.Headers["Authorization"]
|
|
||||||
.ToString()
|
|
||||||
.Replace(JwtBearerDefaults.AuthenticationScheme, string.Empty)
|
|
||||||
.Trim();
|
|
||||||
|
|
||||||
context.Token = accessToken;
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
},
|
|
||||||
OnTokenValidated = context =>
|
|
||||||
{
|
|
||||||
var username = context.Principal?.Claims
|
|
||||||
.FirstOrDefault(e => e.Type == "username")?.Value;
|
|
||||||
|
|
||||||
var password = context.Principal?.Claims
|
|
||||||
.FirstOrDefault(e => e.Type == "password")?.Value;
|
|
||||||
|
|
||||||
var keyCloakUser = configuration
|
|
||||||
.GetSection(nameof(AuthUser))
|
|
||||||
.Get<AuthUser>()!;
|
|
||||||
|
|
||||||
if (username != keyCloakUser.Username || password != keyCloakUser.Password)
|
|
||||||
{
|
|
||||||
context.Fail("username or password did not match");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Security (Swagger)
|
|
||||||
private static void AddKeycloackSecurity(this SwaggerGenOptions options, IConfiguration configuration)
|
|
||||||
{
|
|
||||||
options.AddSecurityDefinition("Keycloack", 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'",
|
|
||||||
Name = "Authorization",
|
|
||||||
In = ParameterLocation.Header,
|
|
||||||
Type = SecuritySchemeType.OAuth2,
|
|
||||||
Flows = new OpenApiOAuthFlows
|
|
||||||
{
|
|
||||||
Implicit = new OpenApiOAuthFlow
|
|
||||||
{
|
|
||||||
AuthorizationUrl = new Uri(configuration["Authentication:AuthorizationUrl"]),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
options.AddSecurityRequirement(new OpenApiSecurityRequirement()
|
|
||||||
{
|
|
||||||
{
|
|
||||||
new OpenApiSecurityScheme
|
|
||||||
{
|
|
||||||
Reference = new OpenApiReference
|
|
||||||
{
|
|
||||||
Type = ReferenceType.SecurityScheme,
|
|
||||||
Id = "Keycloack"
|
|
||||||
},
|
|
||||||
Scheme = "Bearer",
|
|
||||||
Name = "Bearer",
|
|
||||||
In = ParameterLocation.Header,
|
|
||||||
},
|
|
||||||
new List<string>()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void AddDefaultSecurity(this SwaggerGenOptions options, IConfiguration configuration)
|
|
||||||
{
|
|
||||||
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'",
|
|
||||||
Name = "Authorization",
|
|
||||||
In = ParameterLocation.Header,
|
|
||||||
Type = SecuritySchemeType.ApiKey,
|
|
||||||
Scheme = "Bearer",
|
|
||||||
});
|
|
||||||
|
|
||||||
options.AddSecurityRequirement(new OpenApiSecurityRequirement()
|
|
||||||
{
|
|
||||||
{
|
|
||||||
new OpenApiSecurityScheme
|
|
||||||
{
|
|
||||||
Reference = new OpenApiReference
|
|
||||||
{
|
|
||||||
Type = ReferenceType.SecurityScheme,
|
|
||||||
Id = "Bearer"
|
|
||||||
},
|
|
||||||
Scheme = "oauth2",
|
|
||||||
Name = "Bearer",
|
|
||||||
In = ParameterLocation.Header,
|
|
||||||
},
|
|
||||||
new List<string>()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
},
|
},
|
||||||
"dotnetRunMessages": true,
|
"dotnetRunMessages": true,
|
||||||
"applicationUrl": "http://localhost:13616"
|
"applicationUrl": "http://localhost:5032"
|
||||||
},
|
},
|
||||||
"IIS Express": {
|
"IIS Express": {
|
||||||
"commandName": "IISExpress",
|
"commandName": "IISExpress",
|
||||||
|
@ -4,6 +4,5 @@
|
|||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Warning"
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"NeedUseKeyCloak": false
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
{
|
{
|
||||||
"DbConnection": {
|
"DbConnection": {
|
||||||
"Host": "localhost",
|
"Host": "localhost",
|
||||||
"Port": 5432,
|
"Port": 5432,
|
||||||
"Username": "postgres",
|
"Username": "postgres",
|
||||||
"Password": "q"
|
"Password": "q"
|
||||||
},
|
},
|
||||||
"NeedUseKeyCloak": false,
|
"KeycloakTestUser": {
|
||||||
"AuthUser": {
|
|
||||||
"username": "myuser",
|
"username": "myuser",
|
||||||
"password": 12345,
|
"password": 12345,
|
||||||
"clientId": "webapi",
|
"clientId": "webapi",
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
using Persistence.Models;
|
|
||||||
using Refit;
|
|
||||||
|
|
||||||
namespace Persistence.Client.Clients;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Интерфейс для тестирования API, предназначенного для работы с уставками
|
|
||||||
/// </summary>
|
|
||||||
public interface ISetpointClient
|
|
||||||
{
|
|
||||||
private const string BaseRoute = "/api/setpoint";
|
|
||||||
|
|
||||||
[Get($"{BaseRoute}/current")]
|
|
||||||
Task<IApiResponse<IEnumerable<SetpointValueDto>>> GetCurrent([Query(CollectionFormat.Multi)] IEnumerable<Guid> setpointKeys);
|
|
||||||
|
|
||||||
[Get($"{BaseRoute}/history")]
|
|
||||||
Task<IApiResponse<IEnumerable<SetpointValueDto>>> GetHistory([Query(CollectionFormat.Multi)] IEnumerable<Guid> setpointKeys, [Query] DateTimeOffset historyMoment);
|
|
||||||
|
|
||||||
[Get($"{BaseRoute}/log")]
|
|
||||||
Task<IApiResponse<Dictionary<Guid, IEnumerable<SetpointLogDto>>>> GetLog([Query(CollectionFormat.Multi)] IEnumerable<Guid> setpointKeys);
|
|
||||||
|
|
||||||
[Post($"{BaseRoute}/")]
|
|
||||||
Task<IApiResponse> Save(Guid setpointKey, object newValue);
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
using System.IdentityModel.Tokens.Jwt;
|
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Security.Claims;
|
|
||||||
using System.Text.Json;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.IdentityModel.Tokens;
|
|
||||||
using Persistence.Models.Configurations;
|
|
||||||
using RestSharp;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
var jwtToken = needUseKeyCloak
|
|
||||||
? authUser.CreateKeyCloakJwtToken(keycloakGetTokenUrl)
|
|
||||||
: authUser.CreateDefaultJwtToken();
|
|
||||||
|
|
||||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string CreateDefaultJwtToken(this AuthUser authUser)
|
|
||||||
{
|
|
||||||
var claims = new List<Claim>()
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 keyCloackResponse = restClient.Post(request);
|
|
||||||
if (keyCloackResponse.IsSuccessful && !String.IsNullOrEmpty(keyCloackResponse.Content))
|
|
||||||
{
|
|
||||||
var token = JsonSerializer.Deserialize<JwtToken>(keyCloackResponse.Content)!;
|
|
||||||
return token.AccessToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
return String.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.2.1" />
|
|
||||||
<PackageReference Include="Refit" Version="8.0.0" />
|
|
||||||
<PackageReference Include="Refit.HttpClientFactory" Version="8.0.0" />
|
|
||||||
<PackageReference Include="RestSharp" Version="112.1.0" />
|
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.2.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\Persistence\Persistence.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Models\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
@ -1,32 +0,0 @@
|
|||||||
using System.Text.Json;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Persistence.Client.Helpers;
|
|
||||||
using Refit;
|
|
||||||
|
|
||||||
namespace Persistence.Client
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Фабрика клиентов для доступа к Persistence - сервису
|
|
||||||
/// </summary>
|
|
||||||
public class PersistenceClientFactory
|
|
||||||
{
|
|
||||||
private static readonly JsonSerializerOptions JsonSerializerOptions = new()
|
|
||||||
{
|
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
||||||
PropertyNameCaseInsensitive = true
|
|
||||||
};
|
|
||||||
private static readonly RefitSettings RefitSettings = new(new SystemTextJsonContentSerializer(JsonSerializerOptions));
|
|
||||||
private HttpClient httpClient;
|
|
||||||
public PersistenceClientFactory(IHttpClientFactory httpClientFactory, IConfiguration configuration)
|
|
||||||
{
|
|
||||||
this.httpClient = httpClientFactory.CreateClient();
|
|
||||||
|
|
||||||
httpClient.Authorize(configuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T GetClient<T>()
|
|
||||||
{
|
|
||||||
return RestService.For<T>(httpClient, RefitSettings);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace Persistence.Database.Postgres.Migrations
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public partial class SetpointMigration : Migration
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Setpoint",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Key = table.Column<Guid>(type: "uuid", nullable: false, comment: "Ключ"),
|
|
||||||
Created = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата изменения уставки"),
|
|
||||||
Value = table.Column<object>(type: "jsonb", nullable: false, comment: "Значение уставки"),
|
|
||||||
IdUser = table.Column<int>(type: "integer", nullable: false, comment: "Id автора последнего изменения")
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Setpoint", x => new { x.Key, x.Created });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Setpoint");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -12,8 +12,8 @@ using Persistence.Database.Model;
|
|||||||
namespace Persistence.Database.Postgres.Migrations
|
namespace Persistence.Database.Postgres.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(PersistenceDbContext))]
|
[DbContext(typeof(PersistenceDbContext))]
|
||||||
[Migration("20241118052225_SetpointMigration")]
|
[Migration("20241122124437_AddChangeLog")]
|
||||||
partial class SetpointMigration
|
partial class AddChangeLog
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
@ -27,14 +27,48 @@ namespace Persistence.Database.Postgres.Migrations
|
|||||||
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "adminpack");
|
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "adminpack");
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Persistence.Database.Model.ChangeLog", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("Id");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Creation")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("Creation");
|
||||||
|
|
||||||
|
b.Property<int>("IdAuthor")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("IdAuthor");
|
||||||
|
|
||||||
|
b.Property<int?>("IdEditor")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("IdEditor");
|
||||||
|
|
||||||
|
b.Property<int?>("IdNext")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("IdNext");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("Obsolete")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("Obsolete");
|
||||||
|
|
||||||
|
b.Property<object>("Value")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("jsonb")
|
||||||
|
.HasColumnName("Value");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("ChangeLog");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Persistence.Database.Model.DataSaub", b =>
|
modelBuilder.Entity("Persistence.Database.Model.DataSaub", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<DateTimeOffset>("Date")
|
||||||
.ValueGeneratedOnAdd()
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnType("integer")
|
.HasColumnName("date");
|
||||||
.HasColumnName("id");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
|
||||||
|
|
||||||
b.Property<double?>("AxialLoad")
|
b.Property<double?>("AxialLoad")
|
||||||
.HasColumnType("double precision")
|
.HasColumnType("double precision")
|
||||||
@ -100,10 +134,6 @@ namespace Persistence.Database.Postgres.Migrations
|
|||||||
.HasColumnType("double precision")
|
.HasColumnType("double precision")
|
||||||
.HasColumnName("rotorTorque");
|
.HasColumnName("rotorTorque");
|
||||||
|
|
||||||
b.Property<int>("TimeStamp")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.Property<string>("User")
|
b.Property<string>("User")
|
||||||
.HasColumnType("text")
|
.HasColumnType("text")
|
||||||
.HasColumnName("user");
|
.HasColumnName("user");
|
||||||
@ -112,34 +142,10 @@ namespace Persistence.Database.Postgres.Migrations
|
|||||||
.HasColumnType("double precision")
|
.HasColumnType("double precision")
|
||||||
.HasColumnName("wellDepth");
|
.HasColumnName("wellDepth");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Date");
|
||||||
|
|
||||||
b.ToTable("DataSaub");
|
b.ToTable("DataSaub");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Persistence.Database.Model.Setpoint", b =>
|
|
||||||
{
|
|
||||||
b.Property<Guid>("Key")
|
|
||||||
.HasColumnType("uuid")
|
|
||||||
.HasComment("Ключ");
|
|
||||||
|
|
||||||
b.Property<DateTimeOffset>("Created")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasComment("Дата изменения уставки");
|
|
||||||
|
|
||||||
b.Property<int>("IdUser")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasComment("Id автора последнего изменения");
|
|
||||||
|
|
||||||
b.Property<object>("Value")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("jsonb")
|
|
||||||
.HasComment("Значение уставки");
|
|
||||||
|
|
||||||
b.HasKey("Key", "Created");
|
|
||||||
|
|
||||||
b.ToTable("Setpoint");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
#pragma warning restore 612, 618
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Persistence.Database.Postgres.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddChangeLog : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ChangeLog",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
IdAuthor = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
IdEditor = table.Column<int>(type: "integer", nullable: true),
|
||||||
|
Creation = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||||
|
Obsolete = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||||
|
IdNext = table.Column<int>(type: "integer", nullable: true),
|
||||||
|
Value = table.Column<object>(type: "jsonb", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ChangeLog", x => x.Id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ChangeLog");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,43 @@ namespace Persistence.Database.Postgres.Migrations
|
|||||||
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "adminpack");
|
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "adminpack");
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Persistence.Database.Model.ChangeLog", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("Id");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Creation")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("Creation");
|
||||||
|
|
||||||
|
b.Property<int>("IdAuthor")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("IdAuthor");
|
||||||
|
|
||||||
|
b.Property<int?>("IdEditor")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("IdEditor");
|
||||||
|
|
||||||
|
b.Property<int?>("IdNext")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("IdNext");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("Obsolete")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("Obsolete");
|
||||||
|
|
||||||
|
b.Property<object>("Value")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("jsonb")
|
||||||
|
.HasColumnName("Value");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("ChangeLog");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Persistence.Database.Model.DataSaub", b =>
|
modelBuilder.Entity("Persistence.Database.Model.DataSaub", b =>
|
||||||
{
|
{
|
||||||
b.Property<DateTimeOffset>("Date")
|
b.Property<DateTimeOffset>("Date")
|
||||||
@ -106,30 +143,6 @@ namespace Persistence.Database.Postgres.Migrations
|
|||||||
|
|
||||||
b.ToTable("DataSaub");
|
b.ToTable("DataSaub");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Persistence.Database.Model.Setpoint", b =>
|
|
||||||
{
|
|
||||||
b.Property<Guid>("Key")
|
|
||||||
.HasColumnType("uuid")
|
|
||||||
.HasComment("Ключ");
|
|
||||||
|
|
||||||
b.Property<DateTimeOffset>("Created")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasComment("Дата изменения уставки");
|
|
||||||
|
|
||||||
b.Property<int>("IdUser")
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasComment("Id автора последнего изменения");
|
|
||||||
|
|
||||||
b.Property<object>("Value")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("jsonb")
|
|
||||||
.HasComment("Значение уставки");
|
|
||||||
|
|
||||||
b.HasKey("Key", "Created");
|
|
||||||
|
|
||||||
b.ToTable("Setpoint");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
#pragma warning restore 612, 618
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
|
|
||||||
namespace Persistence.Database.Model;
|
namespace Persistence.Database.Model;
|
||||||
public partial class PersistenceDbContext : DbContext, IPersistenceDbContext
|
public partial class PersistenceDbContext : DbContext, IPersistenceDbContext
|
||||||
{
|
{
|
||||||
public DbSet<DataSaub> DataSaub => Set<DataSaub>();
|
public DbSet<DataSaub> DataSaub => Set<DataSaub>();
|
||||||
|
public DbSet<ChangeLog> ChangeLog => Set<ChangeLog>();
|
||||||
public DbSet<Setpoint> Setpoint => Set<Setpoint>();
|
|
||||||
|
|
||||||
public PersistenceDbContext()
|
public PersistenceDbContext()
|
||||||
: base()
|
: base()
|
||||||
|
59
Persistence.Database/Entity/ChangeLog.cs
Normal file
59
Persistence.Database/Entity/ChangeLog.cs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Persistence.Database.Model;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Часть записи, описывающая изменение
|
||||||
|
/// </summary>
|
||||||
|
public class ChangeLog : IChangeLog
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Ид записи
|
||||||
|
/// </summary>
|
||||||
|
[Key, Column("Id")]
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Дискриминатор таблицы
|
||||||
|
/// </summary>
|
||||||
|
[Column("IdDiscriminator")]
|
||||||
|
public Guid IdDiscriminator { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Автор изменения
|
||||||
|
/// </summary>
|
||||||
|
[Column("IdAuthor")]
|
||||||
|
public Guid IdAuthor { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Редактор
|
||||||
|
/// </summary>
|
||||||
|
[Column("IdEditor")]
|
||||||
|
public Guid? IdEditor { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Дата создания записи
|
||||||
|
/// </summary>
|
||||||
|
[Column("Creation")]
|
||||||
|
public DateTimeOffset Creation { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Дата устаревания (например при удалении)
|
||||||
|
/// </summary>
|
||||||
|
[Column("Obsolete")]
|
||||||
|
public DateTimeOffset? Obsolete { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id заменяющей записи
|
||||||
|
/// </summary>
|
||||||
|
[Column("IdNext")]
|
||||||
|
public Guid? IdNext { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Значение
|
||||||
|
/// </summary>
|
||||||
|
[Column("Value", TypeName = "jsonb")]
|
||||||
|
public required object Value { get; set; }
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Persistence.Database.Model;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Часть записи, описывающая изменение данных, содержащие начальную и конечную глубину, а также секцию
|
||||||
|
/// </summary>
|
||||||
|
public class ChangeLogWithWellDepthAndSectionId : ChangeLog
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Глубина забоя на дату начала интервала
|
||||||
|
/// </summary>
|
||||||
|
[Column("DepthStart")]
|
||||||
|
public double? DepthStart { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Глубина забоя на дату окончания интервала
|
||||||
|
/// </summary>
|
||||||
|
[Column("DepthEnd")]
|
||||||
|
public double? DepthEnd { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ключ секции
|
||||||
|
/// </summary>
|
||||||
|
[Column("IdSection")]
|
||||||
|
public Guid IdSection { get; set; }
|
||||||
|
}
|
43
Persistence.Database/Entity/IChangeLog.cs
Normal file
43
Persistence.Database/Entity/IChangeLog.cs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
|
||||||
|
namespace Persistence.Database.Model;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Часть записи описывающая изменение
|
||||||
|
/// </summary>
|
||||||
|
public interface IChangeLog
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Ид записи
|
||||||
|
/// </summary>
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Автор изменения
|
||||||
|
/// </summary>
|
||||||
|
public Guid IdAuthor { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Редактор
|
||||||
|
/// </summary>
|
||||||
|
public Guid? IdEditor { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Дата создания записи
|
||||||
|
/// </summary>
|
||||||
|
public DateTimeOffset Creation { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Дата устаревания (например при удалении)
|
||||||
|
/// </summary>
|
||||||
|
public DateTimeOffset? Obsolete { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id заменяющей записи
|
||||||
|
/// </summary>
|
||||||
|
public Guid? IdNext { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Значение
|
||||||
|
/// </summary>
|
||||||
|
public object Value { get; set; }
|
||||||
|
}
|
@ -1,21 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace Persistence.Database.Model
|
|
||||||
{
|
|
||||||
[PrimaryKey(nameof(Key), nameof(Created))]
|
|
||||||
public class Setpoint
|
|
||||||
{
|
|
||||||
[Comment("Ключ")]
|
|
||||||
public Guid Key { get; set; }
|
|
||||||
|
|
||||||
[Column(TypeName = "jsonb"), Comment("Значение уставки")]
|
|
||||||
public required object Value { get; set; }
|
|
||||||
|
|
||||||
[Comment("Дата создания уставки")]
|
|
||||||
public DateTimeOffset Created { get; set; }
|
|
||||||
|
|
||||||
[Comment("Id автора последнего изменения")]
|
|
||||||
public int IdUser { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,4 +5,5 @@ namespace Persistence.Database;
|
|||||||
public interface IPersistenceDbContext : IDisposable
|
public interface IPersistenceDbContext : IDisposable
|
||||||
{
|
{
|
||||||
DbSet<DataSaub> DataSaub { get; }
|
DbSet<DataSaub> DataSaub { get; }
|
||||||
|
DbSet<ChangeLog> ChangeLog { get; }
|
||||||
}
|
}
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.Metrics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Persistence.Database.Model;
|
|
||||||
public interface IPersistenceDbContext : IDisposable
|
|
||||||
{
|
|
||||||
DbSet<DataSaub> DataSaub { get; }
|
|
||||||
DbSet<Setpoint> Setpoint { get; }
|
|
||||||
DatabaseFacade Database { get; }
|
|
||||||
Task<int> SaveChangesAsync(CancellationToken cancellationToken);
|
|
||||||
}
|
|
43
Persistence.IntegrationTests/ApiTokenHelper.cs
Normal file
43
Persistence.IntegrationTests/ApiTokenHelper.cs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
namespace Persistence.IntegrationTests;
|
||||||
|
public static class ApiTokenHelper
|
||||||
|
{
|
||||||
|
//public static string GetAdminUserToken()
|
||||||
|
//{
|
||||||
|
// var user = new User()
|
||||||
|
// {
|
||||||
|
// Id = 1,
|
||||||
|
// IdCompany = 1,
|
||||||
|
// Login = "test_user"
|
||||||
|
// };
|
||||||
|
// var roles = new[] { "root" };
|
||||||
|
|
||||||
|
// return CreateToken(user, roles);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//private static string CreateToken(User user, IEnumerable<string> roles)
|
||||||
|
//{
|
||||||
|
// var claims = new List<Claim>
|
||||||
|
// {
|
||||||
|
// new("id", user.Id.ToString()),
|
||||||
|
// new(ClaimsIdentity.DefaultNameClaimType, user.Login),
|
||||||
|
// new("idCompany", user.IdCompany.ToString()),
|
||||||
|
// };
|
||||||
|
|
||||||
|
// claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
|
||||||
|
|
||||||
|
// const string secret = "супер секретный ключ для шифрования";
|
||||||
|
|
||||||
|
// var key = Encoding.ASCII.GetBytes(secret);
|
||||||
|
// var tokenDescriptor = new SecurityTokenDescriptor
|
||||||
|
// {
|
||||||
|
// Issuer = "a",
|
||||||
|
// Audience = "a",
|
||||||
|
// Subject = new ClaimsIdentity(claims),
|
||||||
|
// Expires = DateTime.UtcNow.AddHours(1),
|
||||||
|
// SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
|
||||||
|
// };
|
||||||
|
// var tokenHandler = new JwtSecurityTokenHandler();
|
||||||
|
// var token = tokenHandler.CreateToken(tokenDescriptor);
|
||||||
|
// return tokenHandler.WriteToken(token);
|
||||||
|
//}
|
||||||
|
}
|
@ -2,7 +2,7 @@
|
|||||||
using Persistence.Models;
|
using Persistence.Models;
|
||||||
using Refit;
|
using Refit;
|
||||||
|
|
||||||
namespace Persistence.Client.Clients;
|
namespace Persistence.IntegrationTests.Clients;
|
||||||
public interface ITimeSeriesClient<TDto>
|
public interface ITimeSeriesClient<TDto>
|
||||||
where TDto : class, new()
|
where TDto : class, new()
|
||||||
{
|
{
|
@ -1,5 +1,4 @@
|
|||||||
using Persistence.Client;
|
using Persistence.Database.Model;
|
||||||
using Persistence.Database.Model;
|
|
||||||
using Persistence.Repository.Data;
|
using Persistence.Repository.Data;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
@ -1,159 +0,0 @@
|
|||||||
using System.Net;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Persistence.Client;
|
|
||||||
using Persistence.Client.Clients;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace Persistence.IntegrationTests.Controllers
|
|
||||||
{
|
|
||||||
public class SetpointControllerTest : BaseIntegrationTest
|
|
||||||
{
|
|
||||||
private ISetpointClient setpointClient;
|
|
||||||
private class TestObject
|
|
||||||
{
|
|
||||||
public string? value1 { get; set; }
|
|
||||||
public int? value2 { get; set; }
|
|
||||||
}
|
|
||||||
public SetpointControllerTest(WebAppFactoryFixture factory) : base(factory)
|
|
||||||
{
|
|
||||||
var scope = factory.Services.CreateScope();
|
|
||||||
var persistenceClientFactory = scope.ServiceProvider
|
|
||||||
.GetRequiredService<PersistenceClientFactory>();
|
|
||||||
|
|
||||||
setpointClient = persistenceClientFactory.GetClient<ISetpointClient>();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task GetCurrent_returns_success()
|
|
||||||
{
|
|
||||||
//arrange
|
|
||||||
var setpointKeys = new List<Guid>()
|
|
||||||
{
|
|
||||||
Guid.NewGuid(),
|
|
||||||
Guid.NewGuid()
|
|
||||||
};
|
|
||||||
|
|
||||||
//act
|
|
||||||
var response = await setpointClient.GetCurrent(setpointKeys);
|
|
||||||
|
|
||||||
//assert
|
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
||||||
Assert.NotNull(response.Content);
|
|
||||||
Assert.Empty(response.Content);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task GetCurrent_AfterSave_returns_success()
|
|
||||||
{
|
|
||||||
//arrange
|
|
||||||
var setpointKey = await Save();
|
|
||||||
|
|
||||||
//act
|
|
||||||
var response = await setpointClient.GetCurrent([setpointKey]);
|
|
||||||
|
|
||||||
//assert
|
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
||||||
Assert.NotNull(response.Content);
|
|
||||||
Assert.NotEmpty(response.Content);
|
|
||||||
Assert.Equal(setpointKey, response.Content.FirstOrDefault()?.Key);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task GetHistory_returns_success()
|
|
||||||
{
|
|
||||||
//arrange
|
|
||||||
var setpointKeys = new List<Guid>()
|
|
||||||
{
|
|
||||||
Guid.NewGuid(),
|
|
||||||
Guid.NewGuid()
|
|
||||||
};
|
|
||||||
var historyMoment = DateTimeOffset.UtcNow;
|
|
||||||
|
|
||||||
//act
|
|
||||||
var response = await setpointClient.GetHistory(setpointKeys, historyMoment);
|
|
||||||
|
|
||||||
//assert
|
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
||||||
Assert.NotNull(response.Content);
|
|
||||||
Assert.Empty(response.Content);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task GetHistory_AfterSave_returns_success()
|
|
||||||
{
|
|
||||||
//arrange
|
|
||||||
var setpointKey = await Save();
|
|
||||||
var historyMoment = DateTimeOffset.UtcNow;
|
|
||||||
historyMoment = historyMoment.AddDays(1);
|
|
||||||
|
|
||||||
//act
|
|
||||||
var response = await setpointClient.GetHistory([setpointKey], historyMoment);
|
|
||||||
|
|
||||||
//assert
|
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
||||||
Assert.NotNull(response.Content);
|
|
||||||
Assert.NotEmpty(response.Content);
|
|
||||||
Assert.Equal(setpointKey, response.Content.FirstOrDefault()?.Key);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task GetLog_returns_success()
|
|
||||||
{
|
|
||||||
//arrange
|
|
||||||
var setpointKeys = new List<Guid>()
|
|
||||||
{
|
|
||||||
Guid.NewGuid(),
|
|
||||||
Guid.NewGuid()
|
|
||||||
};
|
|
||||||
|
|
||||||
//act
|
|
||||||
var response = await setpointClient.GetLog(setpointKeys);
|
|
||||||
|
|
||||||
//assert
|
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
||||||
Assert.NotNull(response.Content);
|
|
||||||
Assert.Empty(response.Content);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task GetLog_AfterSave_returns_success()
|
|
||||||
{
|
|
||||||
//arrange
|
|
||||||
var setpointKey = await Save();
|
|
||||||
|
|
||||||
//act
|
|
||||||
var response = await setpointClient.GetLog([setpointKey]);
|
|
||||||
|
|
||||||
//assert
|
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
||||||
Assert.NotNull(response.Content);
|
|
||||||
Assert.NotEmpty(response.Content);
|
|
||||||
Assert.Equal(setpointKey, response.Content.FirstOrDefault().Key);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Save_returns_success()
|
|
||||||
{
|
|
||||||
await Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<Guid> Save()
|
|
||||||
{
|
|
||||||
//arrange
|
|
||||||
var setpointKey = Guid.NewGuid();
|
|
||||||
var setpointValue = new TestObject()
|
|
||||||
{
|
|
||||||
value1 = "1",
|
|
||||||
value2 = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
//act
|
|
||||||
var response = await setpointClient.Save(setpointKey, setpointValue);
|
|
||||||
|
|
||||||
//assert
|
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
||||||
|
|
||||||
return setpointKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +1,7 @@
|
|||||||
using System.Net;
|
using Mapster;
|
||||||
using Mapster;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Persistence.Client;
|
|
||||||
using Persistence.Client.Clients;
|
|
||||||
using Persistence.Database.Model;
|
using Persistence.Database.Model;
|
||||||
|
using Persistence.IntegrationTests.Clients;
|
||||||
|
using System.Net;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Persistence.IntegrationTests.Controllers;
|
namespace Persistence.IntegrationTests.Controllers;
|
||||||
@ -11,17 +9,16 @@ public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrat
|
|||||||
where TEntity : class, ITimestampedData, new()
|
where TEntity : class, ITimestampedData, new()
|
||||||
where TDto : class, new()
|
where TDto : class, new()
|
||||||
{
|
{
|
||||||
private ITimeSeriesClient<TDto> timeSeriesClient;
|
private ITimeSeriesClient<TDto> client;
|
||||||
|
|
||||||
public TimeSeriesBaseControllerTest(WebAppFactoryFixture factory) : base(factory)
|
public TimeSeriesBaseControllerTest(WebAppFactoryFixture factory) : base(factory)
|
||||||
{
|
{
|
||||||
dbContext.CleanupDbSet<TEntity>();
|
dbContext.CleanupDbSet<TEntity>();
|
||||||
|
|
||||||
var scope = factory.Services.CreateScope();
|
Task.Run(async () =>
|
||||||
var persistenceClientFactory = scope.ServiceProvider
|
{
|
||||||
.GetRequiredService<PersistenceClientFactory>();
|
client = await factory.GetAuthorizedHttpClient<ITimeSeriesClient<TDto>>(string.Empty);
|
||||||
|
}).Wait();
|
||||||
timeSeriesClient = persistenceClientFactory.GetClient<ITimeSeriesClient<TDto>>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task InsertRangeSuccess(TDto dto)
|
public async Task InsertRangeSuccess(TDto dto)
|
||||||
@ -30,7 +27,7 @@ public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrat
|
|||||||
var expected = dto.Adapt<TDto>();
|
var expected = dto.Adapt<TDto>();
|
||||||
|
|
||||||
//act
|
//act
|
||||||
var response = await timeSeriesClient.InsertRange(new TDto[] { expected });
|
var response = await client.InsertRange(new TDto[] { expected });
|
||||||
|
|
||||||
//assert
|
//assert
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
@ -46,7 +43,7 @@ public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrat
|
|||||||
|
|
||||||
dbContext.SaveChanges();
|
dbContext.SaveChanges();
|
||||||
|
|
||||||
var response = await timeSeriesClient.Get(beginDate, endDate);
|
var response = await client.Get(beginDate, endDate);
|
||||||
|
|
||||||
//assert
|
//assert
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
@ -68,7 +65,7 @@ public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrat
|
|||||||
|
|
||||||
dbContext.SaveChanges();
|
dbContext.SaveChanges();
|
||||||
|
|
||||||
var response = await timeSeriesClient.GetDatesRange();
|
var response = await client.GetDatesRange();
|
||||||
|
|
||||||
//assert
|
//assert
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
@ -98,7 +95,7 @@ public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrat
|
|||||||
|
|
||||||
dbContext.SaveChanges();
|
dbContext.SaveChanges();
|
||||||
|
|
||||||
var response = await timeSeriesClient.GetResampledData(entity.Date.AddMinutes(-1), differenceBetweenStartAndEndDays * 24 * 60 * 60 + 60, approxPointsCount);
|
var response = await client.GetResampledData(entity.Date.AddMinutes(-1), differenceBetweenStartAndEndDays * 24 * 60 * 60 + 60, approxPointsCount);
|
||||||
|
|
||||||
//assert
|
//assert
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
8
Persistence.IntegrationTests/JwtToken.cs
Normal file
8
Persistence.IntegrationTests/JwtToken.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Persistence.IntegrationTests;
|
||||||
|
public class JwtToken
|
||||||
|
{
|
||||||
|
[JsonPropertyName("access_token")]
|
||||||
|
public required string AccessToken { get; set; }
|
||||||
|
}
|
27
Persistence.IntegrationTests/KeyCloakUser.cs
Normal file
27
Persistence.IntegrationTests/KeyCloakUser.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
namespace Persistence.IntegrationTests;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// настройки credentials для пользователя в KeyCloak
|
||||||
|
/// </summary>
|
||||||
|
public class KeyCloakUser
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public required string Username { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public required string Password { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public required string ClientId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public required string GrantType { get; set; }
|
||||||
|
}
|
@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Persistence.API\Persistence.API.csproj" />
|
<ProjectReference Include="..\Persistence.API\Persistence.API.csproj" />
|
||||||
<ProjectReference Include="..\Persistence.Client\Persistence.Client.csproj" />
|
|
||||||
<ProjectReference Include="..\Persistence.Database.Postgres\Persistence.Database.Postgres.csproj" />
|
<ProjectReference Include="..\Persistence.Database.Postgres\Persistence.Database.Postgres.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
namespace Persistence.IntegrationTests
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Фабрика HTTP клиентов для интеграционных тестов
|
|
||||||
/// </summary>
|
|
||||||
public class TestHttpClientFactory : IHttpClientFactory
|
|
||||||
{
|
|
||||||
private readonly WebAppFactoryFixture factory;
|
|
||||||
|
|
||||||
public TestHttpClientFactory(WebAppFactoryFixture factory)
|
|
||||||
{
|
|
||||||
this.factory = factory;
|
|
||||||
}
|
|
||||||
public HttpClient CreateClient(string name)
|
|
||||||
{
|
|
||||||
return factory.CreateClient();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +1,67 @@
|
|||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Mvc.Testing;
|
using Microsoft.AspNetCore.Mvc.Testing;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
||||||
using Persistence.API;
|
using Persistence.API;
|
||||||
using Persistence.Client;
|
|
||||||
using Persistence.Database.Model;
|
using Persistence.Database.Model;
|
||||||
using Persistence.Database.Postgres;
|
using Persistence.Database.Postgres;
|
||||||
|
using Refit;
|
||||||
using RestSharp;
|
using RestSharp;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace Persistence.IntegrationTests;
|
namespace Persistence.IntegrationTests;
|
||||||
public class WebAppFactoryFixture : WebApplicationFactory<Startup>
|
public class WebAppFactoryFixture : WebApplicationFactory<Startup>
|
||||||
{
|
{
|
||||||
private string connectionString = string.Empty;
|
private static readonly JsonSerializerOptions JsonSerializerOptions = new()
|
||||||
|
{
|
||||||
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||||
|
PropertyNameCaseInsensitive = true,
|
||||||
|
//Converters = { new ValidationResultConverter() }
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly RefitSettings RefitSettings = new(new SystemTextJsonContentSerializer(JsonSerializerOptions));
|
||||||
|
|
||||||
|
private readonly string connectionString;
|
||||||
|
private readonly KeyCloakUser keycloakTestUser;
|
||||||
|
public readonly string KeycloakGetTokenUrl;
|
||||||
|
|
||||||
|
public WebAppFactoryFixture()
|
||||||
|
{
|
||||||
|
var configuration = new ConfigurationBuilder()
|
||||||
|
.AddJsonFile("appsettings.Tests.json")
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var dbConnection = configuration.GetSection("DbConnection").Get<DbConnection>()!;
|
||||||
|
connectionString = dbConnection.GetConnectionString();
|
||||||
|
|
||||||
|
keycloakTestUser = configuration.GetSection("KeycloakTestUser").Get<KeyCloakUser>()!;
|
||||||
|
|
||||||
|
KeycloakGetTokenUrl = configuration.GetSection("KeycloakGetTokenUrl").Value!;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
||||||
{
|
{
|
||||||
builder.ConfigureAppConfiguration((hostingContext, config) =>
|
builder.ConfigureServices(services =>
|
||||||
{
|
|
||||||
config.AddJsonFile("appsettings.Tests.json");
|
|
||||||
|
|
||||||
var dbConnection = config.Build().GetSection("DbConnection").Get<DbConnection>()!;
|
|
||||||
connectionString = dbConnection.GetConnectionString();
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.ConfigureServices(services =>
|
|
||||||
{
|
{
|
||||||
var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<PersistenceDbContext>));
|
var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<PersistenceDbContext>));
|
||||||
|
|
||||||
if (descriptor != null)
|
if (descriptor != null)
|
||||||
services.Remove(descriptor);
|
services.Remove(descriptor);
|
||||||
services.AddDbContext<PersistenceDbContext>(options =>
|
|
||||||
|
services.AddDbContext<PersistenceDbContext>(options =>
|
||||||
options.UseNpgsql(connectionString));
|
options.UseNpgsql(connectionString));
|
||||||
|
|
||||||
services.RemoveAll<IHttpClientFactory>();
|
var serviceProvider = services.BuildServiceProvider();
|
||||||
services.AddSingleton<IHttpClientFactory>(provider =>
|
|
||||||
{
|
|
||||||
return new TestHttpClientFactory(this);
|
|
||||||
});
|
|
||||||
|
|
||||||
services.AddSingleton<PersistenceClientFactory>();
|
|
||||||
|
|
||||||
var serviceProvider = services.BuildServiceProvider();
|
|
||||||
|
|
||||||
using var scope = serviceProvider.CreateScope();
|
using var scope = serviceProvider.CreateScope();
|
||||||
var scopedServices = scope.ServiceProvider;
|
var scopedServices = scope.ServiceProvider;
|
||||||
|
|
||||||
var dbContext = scopedServices.GetRequiredService<PersistenceDbContext>();
|
var dbContext = scopedServices.GetRequiredService<PersistenceDbContext>();
|
||||||
|
|
||||||
dbContext.Database.EnsureCreatedAndMigrated();
|
dbContext.Database.EnsureCreatedAndMigrated();
|
||||||
dbContext.SaveChanges();
|
dbContext.SaveChanges();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async ValueTask DisposeAsync()
|
public override async ValueTask DisposeAsync()
|
||||||
@ -61,4 +73,57 @@ public class WebAppFactoryFixture : WebApplicationFactory<Startup>
|
|||||||
|
|
||||||
await dbContext.Database.EnsureDeletedAsync();
|
await dbContext.Database.EnsureDeletedAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public T GetHttpClient<T>(string uriSuffix)
|
||||||
|
{
|
||||||
|
var httpClient = CreateClient();
|
||||||
|
if (string.IsNullOrEmpty(uriSuffix))
|
||||||
|
return RestService.For<T>(httpClient, RefitSettings);
|
||||||
|
|
||||||
|
if (httpClient.BaseAddress is not null)
|
||||||
|
httpClient.BaseAddress = new Uri(httpClient.BaseAddress, uriSuffix);
|
||||||
|
|
||||||
|
return RestService.For<T>(httpClient, RefitSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<T> GetAuthorizedHttpClient<T>(string uriSuffix)
|
||||||
|
{
|
||||||
|
var httpClient = await GetAuthorizedHttpClient();
|
||||||
|
if (string.IsNullOrEmpty(uriSuffix))
|
||||||
|
return RestService.For<T>(httpClient, RefitSettings);
|
||||||
|
|
||||||
|
if (httpClient.BaseAddress is not null)
|
||||||
|
httpClient.BaseAddress = new Uri(httpClient.BaseAddress, uriSuffix);
|
||||||
|
|
||||||
|
return RestService.For<T>(httpClient, RefitSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<HttpClient> GetAuthorizedHttpClient()
|
||||||
|
{
|
||||||
|
var httpClient = CreateClient();
|
||||||
|
var token = await GetTokenAsync();
|
||||||
|
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
||||||
|
|
||||||
|
return httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> GetTokenAsync()
|
||||||
|
{
|
||||||
|
var restClient = new RestClient();
|
||||||
|
|
||||||
|
var request = new RestRequest(KeycloakGetTokenUrl, Method.Post);
|
||||||
|
request.AddParameter("username", keycloakTestUser.Username);
|
||||||
|
request.AddParameter("password", keycloakTestUser.Password);
|
||||||
|
request.AddParameter("client_id", keycloakTestUser.ClientId);
|
||||||
|
request.AddParameter("grant_type", keycloakTestUser.GrantType);
|
||||||
|
|
||||||
|
var keyCloackResponse = await restClient.PostAsync(request);
|
||||||
|
if (keyCloackResponse.IsSuccessful && !String.IsNullOrEmpty(keyCloackResponse.Content))
|
||||||
|
{
|
||||||
|
var token = JsonSerializer.Deserialize<JwtToken>(keyCloackResponse.Content)!;
|
||||||
|
return token.AccessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
return String.Empty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
namespace Persistence.Repository.Data
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Модель для работы с уставкой
|
|
||||||
/// </summary>
|
|
||||||
public class SetpointDto
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Идентификатор уставки
|
|
||||||
/// </summary>
|
|
||||||
public int Id { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Значение уставки
|
|
||||||
/// </summary>
|
|
||||||
public required object Value { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Дата сохранения уставки
|
|
||||||
/// </summary>
|
|
||||||
public DateTimeOffset Edit { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Ключ пользователя
|
|
||||||
/// </summary>
|
|
||||||
public int IdUser { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Persistence.Database.Model;
|
using Persistence.Database.Model;
|
||||||
using Persistence.Repositories;
|
using Persistence.Repositories;
|
||||||
using Persistence.Repository.Data;
|
using Persistence.Repository.Data;
|
||||||
@ -15,8 +15,7 @@ public static class DependencyInjection
|
|||||||
{
|
{
|
||||||
MapsterSetup();
|
MapsterSetup();
|
||||||
|
|
||||||
services.AddTransient<ITimeSeriesDataRepository<DataSaubDto>, TimeSeriesDataRepository<DataSaub, DataSaubDto>>();
|
services.AddTransient<ITimeSeriesDataRepository<DataSaubDto>, TimeSeriesDataCachedRepository<DataSaub, DataSaubDto>>();
|
||||||
services.AddTransient<ISetpointRepository, SetpointRepository>();
|
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
68
Persistence.Repository/Repositories/ChangeLogRepository.cs
Normal file
68
Persistence.Repository/Repositories/ChangeLogRepository.cs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
using Mapster;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Persistence.Database.Model;
|
||||||
|
using Persistence.Models;
|
||||||
|
using Persistence.Repositories;
|
||||||
|
|
||||||
|
namespace Persistence.Repository.Repositories;
|
||||||
|
public class ChangeLogRepository<TDto, TChangeLogDto> : IChangeLogRepository<TDto, TChangeLogDto>
|
||||||
|
where TDto : class, IChangeLogDto, new()
|
||||||
|
where TChangeLogDto : ChangeLogDto<TDto>
|
||||||
|
{
|
||||||
|
private DbContext db;
|
||||||
|
|
||||||
|
public ChangeLogRepository(DbContext db)
|
||||||
|
{
|
||||||
|
this.db = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<int> Clear(int idUser, CancellationToken token)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<int> ClearAndInsertRange(int idUser, IEnumerable<TDto> dtos, CancellationToken token)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<IEnumerable<TChangeLogDto>> GetChangeLogForDate(DateTimeOffset? updateFrom, CancellationToken token)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<IEnumerable<TDto>> GetCurrent(DateTimeOffset moment, CancellationToken token)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<IEnumerable<DateOnly>> GetDatesChange(CancellationToken token)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<IEnumerable<TDto>> GetGtDate(DateTimeOffset dateBegin, CancellationToken token)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<int> InsertRange(int idUser, IEnumerable<TDto> dtos, CancellationToken token)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<int> MarkAsDeleted(int idUser, IEnumerable<int> ids, CancellationToken token)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<int> UpdateOrInsertRange(int idUser, IEnumerable<TDto> dtos, CancellationToken token)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<int> UpdateRange(int idUser, IEnumerable<TDto> dtos, CancellationToken token)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
@ -1,73 +0,0 @@
|
|||||||
using Mapster;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Persistence.Database.Model;
|
|
||||||
using Persistence.Models;
|
|
||||||
using Persistence.Repositories;
|
|
||||||
|
|
||||||
namespace Persistence.Repository.Repositories
|
|
||||||
{
|
|
||||||
public class SetpointRepository : ISetpointRepository
|
|
||||||
{
|
|
||||||
private DbContext db;
|
|
||||||
public SetpointRepository(DbContext db)
|
|
||||||
{
|
|
||||||
this.db = db;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual IQueryable<Setpoint> GetQueryReadOnly() => db.Set<Setpoint>();
|
|
||||||
|
|
||||||
public async Task<IEnumerable<SetpointValueDto>> GetCurrent(IEnumerable<Guid> setpointKeys, CancellationToken token)
|
|
||||||
{
|
|
||||||
var query = GetQueryReadOnly();
|
|
||||||
var entities = await query
|
|
||||||
.Where(e => setpointKeys.Contains(e.Key))
|
|
||||||
.ToArrayAsync(token);
|
|
||||||
var dtos = entities.Select(e => e.Adapt<SetpointValueDto>());
|
|
||||||
|
|
||||||
return dtos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IEnumerable<SetpointValueDto>> GetHistory(IEnumerable<Guid> setpointKeys, DateTimeOffset historyMoment, CancellationToken token)
|
|
||||||
{
|
|
||||||
var query = GetQueryReadOnly();
|
|
||||||
var entities = await query
|
|
||||||
.Where(e => setpointKeys.Contains(e.Key))
|
|
||||||
.ToArrayAsync(token);
|
|
||||||
var filteredEntities = entities
|
|
||||||
.GroupBy(e => e.Key)
|
|
||||||
.Select(e => e.OrderBy(o => o.Created))
|
|
||||||
.Select(e => e.Where(e => e.Created <= historyMoment).Last());
|
|
||||||
var dtos = filteredEntities
|
|
||||||
.Select(e => e.Adapt<SetpointValueDto>());
|
|
||||||
|
|
||||||
return dtos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Dictionary<Guid, IEnumerable<SetpointLogDto>>> GetLog(IEnumerable<Guid> setpointKeys, CancellationToken token)
|
|
||||||
{
|
|
||||||
var query = GetQueryReadOnly();
|
|
||||||
var entities = await query
|
|
||||||
.Where(e => setpointKeys.Contains(e.Key))
|
|
||||||
.ToArrayAsync(token);
|
|
||||||
var dtos = entities
|
|
||||||
.GroupBy(e => e.Key)
|
|
||||||
.ToDictionary(e => e.Key, v => v.Select(z => z.Adapt<SetpointLogDto>()));
|
|
||||||
|
|
||||||
return dtos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Save(Guid setpointKey, object newValue, int idUser, CancellationToken token)
|
|
||||||
{
|
|
||||||
var entity = new Setpoint()
|
|
||||||
{
|
|
||||||
Key = setpointKey,
|
|
||||||
Value = newValue,
|
|
||||||
IdUser = idUser,
|
|
||||||
Created = DateTimeOffset.UtcNow
|
|
||||||
};
|
|
||||||
|
|
||||||
await db.Set<Setpoint>().AddAsync(entity, token);
|
|
||||||
await db.SaveChangesAsync(token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,9 +13,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Persistence.Database", "Per
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Persistence.IntegrationTests", "Persistence.IntegrationTests\Persistence.IntegrationTests.csproj", "{10752C25-3773-4081-A1F2-215A1D950126}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Persistence.IntegrationTests", "Persistence.IntegrationTests\Persistence.IntegrationTests.csproj", "{10752C25-3773-4081-A1F2-215A1D950126}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Persistence.Database.Postgres", "Persistence.Database.Postgres\Persistence.Database.Postgres.csproj", "{CC284D27-162D-490C-B6CF-74D666B7C5F3}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Persistence.Database.Postgres", "Persistence.Database.Postgres\Persistence.Database.Postgres.csproj", "{CC284D27-162D-490C-B6CF-74D666B7C5F3}"
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Persistence.Client", "Persistence.Client\Persistence.Client.csproj", "{84B68660-48E6-4974-A4E5-517552D9DE23}"
|
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@ -47,10 +45,6 @@ Global
|
|||||||
{CC284D27-162D-490C-B6CF-74D666B7C5F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{CC284D27-162D-490C-B6CF-74D666B7C5F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{CC284D27-162D-490C-B6CF-74D666B7C5F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{CC284D27-162D-490C-B6CF-74D666B7C5F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{CC284D27-162D-490C-B6CF-74D666B7C5F3}.Release|Any CPU.Build.0 = Release|Any CPU
|
{CC284D27-162D-490C-B6CF-74D666B7C5F3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{84B68660-48E6-4974-A4E5-517552D9DE23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{84B68660-48E6-4974-A4E5-517552D9DE23}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{84B68660-48E6-4974-A4E5-517552D9DE23}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{84B68660-48E6-4974-A4E5-517552D9DE23}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
|
|
||||||
namespace Persistence.Models;
|
namespace Persistence.Models;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Часть записи описывающая изменение
|
/// Часть записи описывающая изменение
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ChangeLogDto<T> where T: class
|
public class ChangeLogDto<T> : IChangeLogDto
|
||||||
|
where T: class
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Запись
|
/// Запись
|
||||||
@ -11,32 +13,37 @@ public class ChangeLogDto<T> where T: class
|
|||||||
public required T Item { get; set; }
|
public required T Item { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Автор
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public UserDto? Author { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Автор
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public UserDto? Editor { get; set; }
|
public int IdAuthor { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Дата создания записи
|
///
|
||||||
|
/// </summary>
|
||||||
|
public int? IdEditor { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DateTimeOffset Creation { get; set; }
|
public DateTimeOffset Creation { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Дата устаревания (например, при удалении)
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DateTimeOffset? Obsolete { get; set; }
|
public DateTimeOffset? Obsolete { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id состояния
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int IdState { get; set; }
|
public int? IdNext { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id заменяемой записи
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int? IdPrevious { get; set; }
|
public required object Value { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
namespace Persistence.Models.Configurations;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Настройки credentials для авторизации
|
|
||||||
/// </summary>
|
|
||||||
public class AuthUser
|
|
||||||
{
|
|
||||||
public required string Username { get; set; }
|
|
||||||
public required string Password { get; set; }
|
|
||||||
public required string ClientId { get; set; }
|
|
||||||
public required string GrantType { get; set; }
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
using System.Text;
|
|
||||||
using Microsoft.IdentityModel.Tokens;
|
|
||||||
|
|
||||||
namespace Persistence.Models.Configurations
|
|
||||||
{
|
|
||||||
public static class JwtParams
|
|
||||||
{
|
|
||||||
private static readonly string KeyValue = "супер секретный ключ для шифрования";
|
|
||||||
public static SymmetricSecurityKey SecurityKey
|
|
||||||
{
|
|
||||||
get { return new SymmetricSecurityKey(Encoding.ASCII.GetBytes(KeyValue)); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly string Issuer = "a";
|
|
||||||
|
|
||||||
public static readonly string Audience = "a";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Persistence.Models.Configurations
|
|
||||||
{
|
|
||||||
public class JwtToken
|
|
||||||
{
|
|
||||||
[JsonPropertyName("access_token")]
|
|
||||||
public required string AccessToken { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
namespace Persistence.Models;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Часть записи описывающая изменение
|
|
||||||
/// </summary>
|
|
||||||
public interface IChangeLogAbstract
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Актуальная
|
|
||||||
/// </summary>
|
|
||||||
public const int IdStateActual = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Замененная
|
|
||||||
/// </summary>
|
|
||||||
public const int IdStateReplaced = 1;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Удаленная
|
|
||||||
/// </summary>
|
|
||||||
public const int IdStateDeleted = 2;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Очищено при импорте
|
|
||||||
/// </summary>
|
|
||||||
public const int IdCleared = 3;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Ид записи
|
|
||||||
/// </summary>
|
|
||||||
public int Id { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Автор изменения
|
|
||||||
/// </summary>
|
|
||||||
public int IdAuthor { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Редактор
|
|
||||||
/// </summary>
|
|
||||||
public int? IdEditor { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Дата создания записи
|
|
||||||
/// </summary>
|
|
||||||
public DateTimeOffset Creation { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Дата устаревания (например при удалении)
|
|
||||||
/// </summary>
|
|
||||||
public DateTimeOffset? Obsolete { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// "ИД состояния записи: \n0 - актуальная\n1 - замененная\n2 - удаленная
|
|
||||||
/// </summary>
|
|
||||||
public int IdState { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Id заменяемой записи
|
|
||||||
/// </summary>
|
|
||||||
public int? IdPrevious { get; set; }
|
|
||||||
}
|
|
42
Persistence/Models/IChangeLogDto.cs
Normal file
42
Persistence/Models/IChangeLogDto.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
namespace Persistence.Models;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Часть записи описывающая изменение
|
||||||
|
/// </summary>
|
||||||
|
public interface IChangeLogDto
|
||||||
|
{
|
||||||
|
///// <summary>
|
||||||
|
///// Ид записи
|
||||||
|
///// </summary>
|
||||||
|
//public int Id { get; set; }
|
||||||
|
|
||||||
|
///// <summary>
|
||||||
|
///// Автор изменения
|
||||||
|
///// </summary>
|
||||||
|
//public int IdAuthor { get; set; }
|
||||||
|
|
||||||
|
///// <summary>
|
||||||
|
///// Редактор
|
||||||
|
///// </summary>
|
||||||
|
//public int? IdEditor { get; set; }
|
||||||
|
|
||||||
|
///// <summary>
|
||||||
|
///// Дата создания записи
|
||||||
|
///// </summary>
|
||||||
|
//public DateTimeOffset Creation { get; set; }
|
||||||
|
|
||||||
|
///// <summary>
|
||||||
|
///// Дата устаревания (например при удалении)
|
||||||
|
///// </summary>
|
||||||
|
//public DateTimeOffset? Obsolete { get; set; }
|
||||||
|
|
||||||
|
///// <summary>
|
||||||
|
///// Id заменяющей записи
|
||||||
|
///// </summary>
|
||||||
|
//public int? IdNext { get; set; }
|
||||||
|
|
||||||
|
///// <summary>
|
||||||
|
///// Значение
|
||||||
|
///// </summary>
|
||||||
|
//public object Value { get; set; }
|
||||||
|
}
|
11
Persistence/Models/ProcessMapRotorDto.cs
Normal file
11
Persistence/Models/ProcessMapRotorDto.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Persistence.Models;
|
||||||
|
public class ProcessMapRotorDto : IChangeLogDto
|
||||||
|
{
|
||||||
|
public string Caption { get; set; }
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
namespace Persistence.Models;
|
namespace Persistence.Models;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Модель для описания лога уставки
|
/// Модель для описания лога уставки
|
||||||
@ -8,8 +8,8 @@ public class SetpointLogDto : SetpointValueDto
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Дата сохранения уставки
|
/// Дата сохранения уставки
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DateTimeOffset Created { get; set; }
|
public DateTimeOffset DateEdit { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ключ пользователя
|
/// Ключ пользователя
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
namespace Persistence.Models;
|
namespace Persistence.Models;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Модель для хранения значения уставки
|
/// Модель для хранения значения уставки
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SetpointValueDto
|
public class SetpointValueDto
|
||||||
{
|
{
|
||||||
/// Идентификатор уставки
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// Идентификатор уставки
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid Key { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Значение уставки
|
/// Значение уставки
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public required object Value { get; set; }
|
public object Value { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
|
||||||
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.2.1" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -7,7 +7,7 @@ namespace Persistence.Repositories;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TDto"></typeparam>
|
/// <typeparam name="TDto"></typeparam>
|
||||||
public interface IChangeLogRepository<TDto, TChangeLogDto> : ISyncRepository<TDto>
|
public interface IChangeLogRepository<TDto, TChangeLogDto> : ISyncRepository<TDto>
|
||||||
where TDto : class, ITimeSeriesAbstractDto, new()
|
where TDto : class, IChangeLogDto, new()
|
||||||
where TChangeLogDto : ChangeLogDto<TDto>
|
where TChangeLogDto : ChangeLogDto<TDto>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using Persistence.Models;
|
using Persistence.Models;
|
||||||
|
|
||||||
namespace Persistence.Repositories;
|
namespace Persistence.Repositories;
|
||||||
|
|
||||||
@ -7,30 +7,23 @@ namespace Persistence.Repositories;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ISetpointRepository
|
public interface ISetpointRepository
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Получить значения уставок по набору ключей
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="setpointKeys"></param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<IEnumerable<SetpointValueDto>> GetCurrent(IEnumerable<Guid> setpointKeys, CancellationToken token);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получить значения уставок за определенный момент времени
|
/// Получить значения уставок за определенный момент времени
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="setpointKeys"></param>
|
/// <param name="setpoitKeys"></param>
|
||||||
/// <param name="historyMoment">дата, на которую получаем данные</param>
|
/// <param name="historyMoment">дата, на которую получаем данные</param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<IEnumerable<SetpointValueDto>> GetHistory(IEnumerable<Guid> setpointKeys, DateTimeOffset historyMoment, CancellationToken token);
|
Task<IEnumerable<SetpointValueDto>> GetHistory(IEnumerable<Guid> setpoitKeys, DateTimeOffset historyMoment, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получить историю изменений значений уставок
|
/// Получить историю изменений значений уставок
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="setpointKeys"></param>
|
/// <param name="setpoitKeys"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<Dictionary<Guid, IEnumerable<SetpointLogDto>>> GetLog(IEnumerable<Guid> setpointKeys, CancellationToken token);
|
Task<Dictionary<Guid, IEnumerable<SetpointLogDto>>> GetLog(IEnumerable<Guid> setpoitKeys, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Метод сохранения уставки
|
/// Метод сохранения уставки
|
||||||
@ -42,5 +35,5 @@ public interface ISetpointRepository
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// to do
|
/// to do
|
||||||
/// id User учесть в соответствующем методе репозитория
|
/// id User учесть в соответствующем методе репозитория
|
||||||
Task Save(Guid setpointKey, object newValue, int idUser, CancellationToken token);
|
Task<int> Save(Guid setpointKey, int idUser, object newValue, CancellationToken token);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user