using ErsatzTV.Core; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Interfaces.Repositories; using ErsatzTV.Core.Iptv; namespace ErsatzTV.Application.Configuration; public class UpdateIptvSettingsHandler(IConfigElementRepository configElementRepository) : IRequestHandler> { public async Task> Handle( UpdateIptvSettings request, CancellationToken cancellationToken) { Validation validation = Validate(request); return await validation.Apply(_ => ApplyUpdate(request.IptvSettings, cancellationToken)); } private async Task ApplyUpdate(IptvSettingsViewModel iptvSettings, CancellationToken cancellationToken) { string baseUrl = (iptvSettings.BaseUrl ?? string.Empty).Trim(); // A blank value clears the setting so the request-derived behavior is restored. if (string.IsNullOrWhiteSpace(baseUrl)) { await configElementRepository.Delete(ConfigElementKey.IptvBaseUrl, cancellationToken); } else { await configElementRepository.Upsert(ConfigElementKey.IptvBaseUrl, baseUrl, cancellationToken); } return Unit.Default; } private static Validation Validate(UpdateIptvSettings request) { string baseUrl = request.IptvSettings.BaseUrl; // Blank is valid (clears the override); a non-blank value must be a well-formed advertised base URL. if (string.IsNullOrWhiteSpace(baseUrl)) { return Unit.Default; } return AdvertisedBaseUrl.TryParse(baseUrl) .Map(_ => Unit.Default) .ToValidation( "Advertised base URL must be an absolute http(s) URL with no credentials, query, or fragment"); } }