переход на реальное api
This commit is contained in:
+1
-1
@@ -20,7 +20,7 @@ public static class InfrastructureServiceCollectionExtensions
|
||||
|
||||
services.Configure<TnsuPortalOptions>(configuration.GetSection("TnsuPortal"));
|
||||
services.AddHttpClient<TnsuPortalTokenProvider>();
|
||||
services.AddHttpClient<HttpTnsuPortalClient>((sp, client) =>
|
||||
services.AddHttpClient<ITnsuPortalClient, HttpTnsuPortalClient>((sp, client) =>
|
||||
{
|
||||
var options = sp.GetRequiredService<IOptions<TnsuPortalOptions>>().Value;
|
||||
client.BaseAddress = new Uri(options.BaseUrl);
|
||||
|
||||
@@ -22,8 +22,10 @@ public class ApprovalRouteDbContext(DbContextOptions<ApprovalRouteDbContext> opt
|
||||
{
|
||||
e.HasKey(x => x.Id);
|
||||
e.Property(x => x.RouteType).HasConversion<string>().HasMaxLength(32).IsRequired();
|
||||
e.Property(x => x.Company).HasMaxLength(256).IsRequired();
|
||||
e.Property(x => x.Department).HasMaxLength(256);
|
||||
e.HasOne(x => x.RequestType).WithMany(x => x.Routes).HasForeignKey(x => x.RequestTypeId);
|
||||
e.HasIndex(x => new { x.RequestTypeId, x.DepartmentId, x.CompanyId, x.ByProject }).IsUnique();
|
||||
e.HasIndex(x => new { x.RequestTypeId, x.Department, x.Company, x.ByProject }).IsUnique();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<TemplateRouteStep>(e =>
|
||||
|
||||
+12
-9
@@ -12,7 +12,7 @@ using Tnsu.ApprovalRoute.Infrastructure.Persistence;
|
||||
namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApprovalRouteDbContext))]
|
||||
[Migration("20260723074943_InitialCreate")]
|
||||
[Migration("20260724071302_InitialCreate")]
|
||||
partial class InitialCreate
|
||||
{
|
||||
/// <inheritdoc />
|
||||
@@ -61,13 +61,16 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("by_project");
|
||||
|
||||
b.Property<Guid>("CompanyId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("company_id");
|
||||
b.Property<string>("Company")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("company");
|
||||
|
||||
b.Property<Guid?>("DepartmentId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("department_id");
|
||||
b.Property<string>("Department")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("department");
|
||||
|
||||
b.Property<Guid>("RequestTypeId")
|
||||
.HasColumnType("uuid")
|
||||
@@ -86,9 +89,9 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_template_routes");
|
||||
|
||||
b.HasIndex("RequestTypeId", "DepartmentId", "CompanyId", "ByProject")
|
||||
b.HasIndex("RequestTypeId", "Department", "Company", "ByProject")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_template_routes_request_type_id_department_id_company_id_by");
|
||||
.HasDatabaseName("ix_template_routes_request_type_id_department_company_by_proje");
|
||||
|
||||
b.ToTable("template_routes", (string)null);
|
||||
});
|
||||
+4
-4
@@ -31,8 +31,8 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
|
||||
id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
route_type = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
||||
request_type_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
department_id = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
company_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
department = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
company = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||
by_project = table.Column<bool>(type: "boolean", nullable: false),
|
||||
requires_control = table.Column<bool>(type: "boolean", nullable: false)
|
||||
},
|
||||
@@ -78,9 +78,9 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
|
||||
columns: new[] { "route_id", "order_no" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_template_routes_request_type_id_department_id_company_id_by",
|
||||
name: "ix_template_routes_request_type_id_department_company_by_proje",
|
||||
table: "template_routes",
|
||||
columns: new[] { "request_type_id", "department_id", "company_id", "by_project" },
|
||||
columns: new[] { "request_type_id", "department", "company", "by_project" },
|
||||
unique: true);
|
||||
}
|
||||
|
||||
+11
-8
@@ -58,13 +58,16 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("by_project");
|
||||
|
||||
b.Property<Guid>("CompanyId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("company_id");
|
||||
b.Property<string>("Company")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("company");
|
||||
|
||||
b.Property<Guid?>("DepartmentId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("department_id");
|
||||
b.Property<string>("Department")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("department");
|
||||
|
||||
b.Property<Guid>("RequestTypeId")
|
||||
.HasColumnType("uuid")
|
||||
@@ -83,9 +86,9 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_template_routes");
|
||||
|
||||
b.HasIndex("RequestTypeId", "DepartmentId", "CompanyId", "ByProject")
|
||||
b.HasIndex("RequestTypeId", "Department", "Company", "ByProject")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_template_routes_request_type_id_department_id_company_id_by");
|
||||
.HasDatabaseName("ix_template_routes_request_type_id_department_company_by_proje");
|
||||
|
||||
b.ToTable("template_routes", (string)null);
|
||||
});
|
||||
|
||||
@@ -1,20 +1,74 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Tnsu.ApprovalRoute.Domain.Enums;
|
||||
|
||||
namespace Tnsu.ApprovalRoute.Infrastructure.TnsuPortal;
|
||||
|
||||
// Клиент api.tnsu.kz (api-tnsu-portal). GetEmployeeByEmailAsync и GetProjectExecutorsAsync — заглушки:
|
||||
// на момент написания у api-tnsu-portal нет эндпоинта GET /Employee/ByEmail (есть только ByIIN/Manager),
|
||||
// а форма ответа GET /Project/{oid} в его openapi-спеке не типизирована. Заменить на реальные вызовы,
|
||||
// когда эндпоинты будут готовы — токен уже прокидывается через TnsuPortalTokenProvider.
|
||||
public sealed class HttpTnsuPortalClient(HttpClient httpClient, TnsuPortalTokenProvider tokenProvider)
|
||||
// Клиент api.tnsu.kz (api-tnsu-portal). Сервисный токен прокидывается через TnsuPortalTokenProvider.
|
||||
public sealed class HttpTnsuPortalClient(HttpClient httpClient, TnsuPortalTokenProvider tokenProvider) : ITnsuPortalClient
|
||||
{
|
||||
public Task<EmployeeDirectoryInfo> GetEmployeeByEmailAsync(string email, CancellationToken cancellationToken)
|
||||
public async Task<EmployeeDirectoryInfo?> GetEmployeeByEmailAsync(string email, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(new EmployeeDirectoryInfo(
|
||||
DepartmentId: Guid.Parse("00000000-0000-0000-0000-000000000001"),
|
||||
CompanyId: Guid.Parse("00000000-0000-0000-0000-000000000002")));
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, $"/Employee/ByEmail?email={Uri.EscapeDataString(email)}");
|
||||
await AuthorizeAsync(request, cancellationToken);
|
||||
|
||||
using var response = await httpClient.SendAsync(request, cancellationToken);
|
||||
if (response.StatusCode == HttpStatusCode.NotFound)
|
||||
return null;
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var employee = await response.Content.ReadFromJsonAsync<EmployeeResponse>(cancellationToken);
|
||||
if (employee is null)
|
||||
return null;
|
||||
|
||||
return new EmployeeDirectoryInfo(employee.Company ?? string.Empty, employee.Section ?? string.Empty);
|
||||
}
|
||||
|
||||
public Task<IReadOnlyList<ProjectExecutorInfo>> GetProjectExecutorsAsync(Guid projectId, CancellationToken cancellationToken)
|
||||
public async Task<IReadOnlyList<ProjectExecutorInfo>> GetProjectExecutorsAsync(Guid projectId, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult<IReadOnlyList<ProjectExecutorInfo>>([]);
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, $"/Project/{projectId}");
|
||||
await AuthorizeAsync(request, cancellationToken);
|
||||
|
||||
using var response = await httpClient.SendAsync(request, cancellationToken);
|
||||
if (response.StatusCode == HttpStatusCode.NotFound)
|
||||
return [];
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var project = await response.Content.ReadFromJsonAsync<ProjectResponse>(cancellationToken);
|
||||
if (project is null)
|
||||
return [];
|
||||
|
||||
// Каждая роль проекта — email сотрудника в соответствующем поле (project_manager / planner / manager_hse / security).
|
||||
var executors = new List<ProjectExecutorInfo>();
|
||||
AddIfPresent(executors, ProjectRole.ProjectManager, project.ProjectManager);
|
||||
AddIfPresent(executors, ProjectRole.Planner, project.Planner);
|
||||
AddIfPresent(executors, ProjectRole.ManagerHSE, project.ManagerHSE);
|
||||
AddIfPresent(executors, ProjectRole.Security, project.Security);
|
||||
|
||||
return executors;
|
||||
}
|
||||
|
||||
private static void AddIfPresent(List<ProjectExecutorInfo> executors, ProjectRole role, string? email)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(email))
|
||||
executors.Add(new ProjectExecutorInfo(role, email));
|
||||
}
|
||||
|
||||
private async Task AuthorizeAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
var token = await tokenProvider.GetAccessTokenAsync(cancellationToken);
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
||||
}
|
||||
|
||||
private sealed record EmployeeResponse(
|
||||
[property: JsonPropertyName("company")] string? Company,
|
||||
[property: JsonPropertyName("section")] string? Section);
|
||||
|
||||
private sealed record ProjectResponse(
|
||||
[property: JsonPropertyName("projectManager")] string? ProjectManager,
|
||||
[property: JsonPropertyName("planner")] string? Planner,
|
||||
[property: JsonPropertyName("managerHSE")] string? ManagerHSE,
|
||||
[property: JsonPropertyName("security")] string? Security);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Tnsu.ApprovalRoute.Infrastructure.TnsuPortal;
|
||||
|
||||
public interface ITnsuPortalClient
|
||||
{
|
||||
Task<EmployeeDirectoryInfo?> GetEmployeeByEmailAsync(string email, CancellationToken cancellationToken);
|
||||
|
||||
Task<IReadOnlyList<ProjectExecutorInfo>> GetProjectExecutorsAsync(Guid projectId, CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -2,6 +2,6 @@ using Tnsu.ApprovalRoute.Domain.Enums;
|
||||
|
||||
namespace Tnsu.ApprovalRoute.Infrastructure.TnsuPortal;
|
||||
|
||||
public sealed record EmployeeDirectoryInfo(Guid DepartmentId, Guid CompanyId);
|
||||
public sealed record EmployeeDirectoryInfo(string Company, string Department);
|
||||
|
||||
public sealed record ProjectExecutorInfo(string Email, string Position, ProjectRole ProjectRole);
|
||||
public sealed record ProjectExecutorInfo(ProjectRole ProjectRole, string Email);
|
||||
|
||||
Reference in New Issue
Block a user