- Add ReactivatePipeline to handle subscription reactivation, including scaling Docker services, health verification, status updates, audit logging, and broadcasting status changes. - Introduce RotateCredentialsPipeline for OAuth2 credential rotation, managing the deletion of old apps, creation of new ones, credential storage, access verification, and audit logging. - Create StepRunner to manage job step execution, including lifecycle management and progress broadcasting via SignalR. - Implement SuspendPipeline for subscription suspension, scaling down services, updating statuses, logging audits, and broadcasting changes. - Add UpdateScreenLimitPipeline to update Xibo CMS screen limits and record snapshots. - Introduce XiboFeatureManifests for hardcoded feature ACLs per role. - Add docker-compose.dev.yml for local development with PostgreSQL setup.
153 lines
5.0 KiB
C#
153 lines
5.0 KiB
C#
using Refit;
|
|
|
|
namespace OTSSignsOrchestrator.Desktop.Services;
|
|
|
|
// ── DTOs matching server REST API responses ─────────────────────────────────
|
|
|
|
public record FleetSummaryDto
|
|
{
|
|
public Guid CustomerId { get; init; }
|
|
public string Abbreviation { get; init; } = string.Empty;
|
|
public string CompanyName { get; init; } = string.Empty;
|
|
public string Plan { get; init; } = string.Empty;
|
|
public int ScreenCount { get; init; }
|
|
public string HealthStatus { get; init; } = "Unknown";
|
|
public DateTime? LastHealthCheck { get; init; }
|
|
public bool HasRunningJob { get; init; }
|
|
}
|
|
|
|
public record CustomerDetailDto
|
|
{
|
|
public Guid Id { get; init; }
|
|
public string Abbreviation { get; init; } = string.Empty;
|
|
public string CompanyName { get; init; } = string.Empty;
|
|
public string? AdminEmail { get; init; }
|
|
public string Plan { get; init; } = string.Empty;
|
|
public int ScreenCount { get; init; }
|
|
public string Status { get; init; } = string.Empty;
|
|
public DateTime CreatedAt { get; init; }
|
|
public List<CustomerInstanceDto> Instances { get; init; } = [];
|
|
public List<CustomerJobDto> ActiveJobs { get; init; } = [];
|
|
}
|
|
|
|
public record CustomerInstanceDto
|
|
{
|
|
public Guid Id { get; init; }
|
|
public string? XiboUrl { get; init; }
|
|
public string? DockerStackName { get; init; }
|
|
public string HealthStatus { get; init; } = "Unknown";
|
|
public DateTime? LastHealthCheck { get; init; }
|
|
}
|
|
|
|
public record CustomerJobDto
|
|
{
|
|
public Guid Id { get; init; }
|
|
public string JobType { get; init; } = string.Empty;
|
|
public string Status { get; init; } = string.Empty;
|
|
public DateTime CreatedAt { get; init; }
|
|
public DateTime? StartedAt { get; init; }
|
|
}
|
|
|
|
public record CreateJobRequest(Guid CustomerId, string JobType, string? Parameters);
|
|
|
|
public record CreateJobResponse
|
|
{
|
|
public Guid Id { get; init; }
|
|
public string JobType { get; init; } = string.Empty;
|
|
public string Status { get; init; } = string.Empty;
|
|
}
|
|
|
|
public record JobDetailDto
|
|
{
|
|
public Guid Id { get; init; }
|
|
public Guid CustomerId { get; init; }
|
|
public string JobType { get; init; } = string.Empty;
|
|
public string Status { get; init; } = string.Empty;
|
|
public string? TriggeredBy { get; init; }
|
|
public string? Parameters { get; init; }
|
|
public DateTime CreatedAt { get; init; }
|
|
public DateTime? StartedAt { get; init; }
|
|
public DateTime? CompletedAt { get; init; }
|
|
public string? ErrorMessage { get; init; }
|
|
public List<JobStepDto> Steps { get; init; } = [];
|
|
}
|
|
|
|
public record JobStepDto
|
|
{
|
|
public Guid Id { get; init; }
|
|
public string StepName { get; init; } = string.Empty;
|
|
public string Status { get; init; } = string.Empty;
|
|
public string? LogOutput { get; init; }
|
|
public DateTime? StartedAt { get; init; }
|
|
public DateTime? CompletedAt { get; init; }
|
|
}
|
|
|
|
public record LoginRequest(string Email, string Password);
|
|
public record RefreshRequest(string RefreshToken);
|
|
|
|
public record AuthResponse
|
|
{
|
|
public string Token { get; init; } = string.Empty;
|
|
public string RefreshToken { get; init; } = string.Empty;
|
|
}
|
|
|
|
public record RefreshResponse
|
|
{
|
|
public string Token { get; init; } = string.Empty;
|
|
}
|
|
|
|
// ── Refit interface ─────────────────────────────────────────────────────────
|
|
|
|
[Headers("Accept: application/json")]
|
|
public interface IServerApiClient
|
|
{
|
|
[Get("/api/fleet")]
|
|
Task<List<FleetSummaryDto>> GetFleetAsync();
|
|
|
|
[Get("/api/fleet/{id}")]
|
|
Task<CustomerDetailDto> GetCustomerDetailAsync(Guid id);
|
|
|
|
[Post("/api/jobs")]
|
|
Task<CreateJobResponse> CreateJobAsync([Body] CreateJobRequest body);
|
|
|
|
[Get("/api/jobs/{id}")]
|
|
Task<JobDetailDto> GetJobAsync(Guid id);
|
|
|
|
[Post("/api/auth/login")]
|
|
Task<AuthResponse> LoginAsync([Body] LoginRequest body);
|
|
|
|
[Post("/api/auth/refresh")]
|
|
Task<RefreshResponse> RefreshAsync([Body] RefreshRequest body);
|
|
|
|
[Get("/api/reports/billing")]
|
|
Task<HttpResponseMessage> GetBillingCsvAsync([Query] DateOnly from, [Query] DateOnly to);
|
|
|
|
[Get("/api/reports/fleet-health")]
|
|
Task<HttpResponseMessage> GetFleetHealthPdfAsync();
|
|
|
|
[Post("/api/fleet/bulk/{action}")]
|
|
Task<HttpResponseMessage> BulkActionAsync(string action);
|
|
}
|
|
|
|
// ── DelegatingHandler for Bearer token injection ────────────────────────────
|
|
|
|
public class AuthHeaderHandler : DelegatingHandler
|
|
{
|
|
private readonly TokenStoreService _tokenStore;
|
|
|
|
public AuthHeaderHandler(TokenStoreService tokenStore)
|
|
{
|
|
_tokenStore = tokenStore;
|
|
}
|
|
|
|
protected override async Task<HttpResponseMessage> SendAsync(
|
|
HttpRequestMessage request, CancellationToken cancellationToken)
|
|
{
|
|
var jwt = _tokenStore.GetJwt();
|
|
if (!string.IsNullOrEmpty(jwt))
|
|
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", jwt);
|
|
|
|
return await base.SendAsync(request, cancellationToken);
|
|
}
|
|
}
|