Feature/routes export (#29)
Tests / backend-test (push) Successful in 6m7s
Tests / frontend-test (push) Successful in 1m29s

Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz>
Reviewed-on: http://git.tnsu.kz/gorbenko.pavel/tnsu-approval-route/pulls/29
This commit was merged in pull request #29.
This commit is contained in:
2026-10-14 05:06:58 +00:00
parent 05f73d356a
commit 0e6a7064d2
21 changed files with 832 additions and 28 deletions
@@ -30,6 +30,12 @@ public sealed class CachingTnsuPortalClient(HttpTnsuPortalClient inner, IMemoryC
public Task<IReadOnlyList<EmployeeContactInfo>> GetAllEmployeesAsync(CancellationToken cancellationToken) =>
GetOrAddAsync("emp:all", () => inner.GetAllEmployeesAsync(cancellationToken));
public Task<IReadOnlyList<CompanyInfo>> GetCompaniesAsync(CancellationToken cancellationToken) =>
GetOrAddAsync("dict:companies", () => inner.GetCompaniesAsync(cancellationToken));
public Task<IReadOnlyList<DepartmentInfo>> GetDepartmentsAsync(CancellationToken cancellationToken) =>
GetOrAddAsync("dict:departments", () => inner.GetDepartmentsAsync(cancellationToken));
public Task<string?> GetManagerAsync(string email, string managerType, CancellationToken cancellationToken) =>
GetOrAddAsync(
$"mgr:{email.ToLowerInvariant()}|{managerType.ToLowerInvariant()}",
@@ -40,7 +40,27 @@ public sealed class HttpTnsuPortalClient(
return employees
.Where(e => !string.IsNullOrWhiteSpace(e.Fio))
.Select(e => new EmployeeContactInfo(e.Id, e.Fio!, e.Email, e.Company ?? string.Empty))
.Select(e => new EmployeeContactInfo(e.Id, e.Fio!, e.Email, e.Company ?? string.Empty, e.Position))
.ToList();
}
// /Dictionary/* отдаёт «голый» массив с ключами в PascalCase (Id/Name) —
// PropertyNameCaseInsensitive в JsonOptions это покрывает.
public async Task<IReadOnlyList<CompanyInfo>> GetCompaniesAsync(CancellationToken cancellationToken)
{
var companies = await GetAsync<List<DictionaryItemResponse>>("/Dictionary/Companies", cancellationToken);
return (companies ?? [])
.Where(c => c.Id is not null && !string.IsNullOrWhiteSpace(c.Name))
.Select(c => new CompanyInfo(c.Id!.Value, c.Name!))
.ToList();
}
public async Task<IReadOnlyList<DepartmentInfo>> GetDepartmentsAsync(CancellationToken cancellationToken)
{
var departments = await GetAsync<List<DictionaryItemResponse>>("/Dictionary/Departments", cancellationToken);
return (departments ?? [])
.Where(d => d.Id is not null && !string.IsNullOrWhiteSpace(d.Name))
.Select(d => new DepartmentInfo(d.Id!.Value, d.Name!))
.ToList();
}
@@ -121,6 +141,10 @@ public sealed class HttpTnsuPortalClient(
[property: JsonPropertyName("fio")] string? Fio,
[property: JsonPropertyName("id")] Guid? Id = null);
private sealed record DictionaryItemResponse(
[property: JsonPropertyName("id")] Guid? Id,
[property: JsonPropertyName("name")] string? Name);
private sealed record ManagerResponse(
[property: JsonPropertyName("managerEmail")] string? ManagerEmail);
@@ -20,6 +20,12 @@ public interface ITnsuPortalClient
/// </summary>
Task<IReadOnlyList<EmployeeContactInfo>> GetAllEmployeesAsync(CancellationToken cancellationToken);
/// <summary>Справочник компаний — /Dictionary/Companies.</summary>
Task<IReadOnlyList<CompanyInfo>> GetCompaniesAsync(CancellationToken cancellationToken);
/// <summary>Справочник отделов — /Dictionary/Departments.</summary>
Task<IReadOnlyList<DepartmentInfo>> GetDepartmentsAsync(CancellationToken cancellationToken);
Task<string?> GetManagerAsync(string email, string managerType, CancellationToken cancellationToken);
/// <summary>
@@ -30,4 +30,10 @@ public sealed record EmployeeFullBaseInfo(Guid? Id, string Fio, string Company,
/// увольнения (в отличие от /Employee/FullBase). Связать одну базу с другой можно
/// по <paramref name="Id"/> — он один и тот же в обоих ответах.
/// </summary>
public sealed record EmployeeContactInfo(Guid? Id, string Fio, string? Email, string Company);
public sealed record EmployeeContactInfo(Guid? Id, string Fio, string? Email, string Company, string? Position = null);
/// <summary>Компания из справочника /Dictionary/Companies.</summary>
public sealed record CompanyInfo(Guid Id, string Name);
/// <summary>Отдел из справочника /Dictionary/Departments.</summary>
public sealed record DepartmentInfo(Guid Id, string Name);