mirror of
https://github.com/Cleanuparr/Cleanuparr.git
synced 2026-01-15 17:28:26 -05:00
1325 lines
49 KiB
C#
1325 lines
49 KiB
C#
using System.Net;
|
|
using Cleanuparr.Api.Features.Notifications.Contracts.Requests;
|
|
using Cleanuparr.Api.Features.Notifications.Contracts.Responses;
|
|
using Cleanuparr.Domain.Enums;
|
|
using Cleanuparr.Domain.Exceptions;
|
|
using Cleanuparr.Infrastructure.Features.Notifications;
|
|
using Cleanuparr.Infrastructure.Features.Notifications.Apprise;
|
|
using Cleanuparr.Infrastructure.Features.Notifications.Discord;
|
|
using Cleanuparr.Infrastructure.Features.Notifications.Models;
|
|
using Cleanuparr.Infrastructure.Features.Notifications.Telegram;
|
|
using Cleanuparr.Persistence;
|
|
using Cleanuparr.Persistence.Models.Configuration.Notification;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace Cleanuparr.Api.Features.Notifications.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("api/configuration/notification_providers")]
|
|
public sealed class NotificationProvidersController : ControllerBase
|
|
{
|
|
private readonly ILogger<NotificationProvidersController> _logger;
|
|
private readonly DataContext _dataContext;
|
|
private readonly INotificationConfigurationService _notificationConfigurationService;
|
|
private readonly NotificationService _notificationService;
|
|
private readonly IAppriseCliDetector _appriseCliDetector;
|
|
|
|
public NotificationProvidersController(
|
|
ILogger<NotificationProvidersController> logger,
|
|
DataContext dataContext,
|
|
INotificationConfigurationService notificationConfigurationService,
|
|
NotificationService notificationService,
|
|
IAppriseCliDetector appriseCliDetector)
|
|
{
|
|
_logger = logger;
|
|
_dataContext = dataContext;
|
|
_notificationConfigurationService = notificationConfigurationService;
|
|
_notificationService = notificationService;
|
|
_appriseCliDetector = appriseCliDetector;
|
|
}
|
|
|
|
[HttpGet]
|
|
public async Task<IActionResult> GetNotificationProviders()
|
|
{
|
|
await DataContext.Lock.WaitAsync();
|
|
try
|
|
{
|
|
var providers = await _dataContext.NotificationConfigs
|
|
.Include(p => p.NotifiarrConfiguration)
|
|
.Include(p => p.AppriseConfiguration)
|
|
.Include(p => p.NtfyConfiguration)
|
|
.Include(p => p.PushoverConfiguration)
|
|
.Include(p => p.TelegramConfiguration)
|
|
.Include(p => p.DiscordConfiguration)
|
|
.AsNoTracking()
|
|
.ToListAsync();
|
|
|
|
var providerDtos = providers
|
|
.Select(p => new NotificationProviderResponse
|
|
{
|
|
Id = p.Id,
|
|
Name = p.Name,
|
|
Type = p.Type,
|
|
IsEnabled = p.IsEnabled,
|
|
Events = new NotificationEventFlags
|
|
{
|
|
OnFailedImportStrike = p.OnFailedImportStrike,
|
|
OnStalledStrike = p.OnStalledStrike,
|
|
OnSlowStrike = p.OnSlowStrike,
|
|
OnQueueItemDeleted = p.OnQueueItemDeleted,
|
|
OnDownloadCleaned = p.OnDownloadCleaned,
|
|
OnCategoryChanged = p.OnCategoryChanged
|
|
},
|
|
Configuration = p.Type switch
|
|
{
|
|
NotificationProviderType.Notifiarr => p.NotifiarrConfiguration ?? new object(),
|
|
NotificationProviderType.Apprise => p.AppriseConfiguration ?? new object(),
|
|
NotificationProviderType.Ntfy => p.NtfyConfiguration ?? new object(),
|
|
NotificationProviderType.Pushover => p.PushoverConfiguration ?? new object(),
|
|
NotificationProviderType.Telegram => p.TelegramConfiguration ?? new object(),
|
|
NotificationProviderType.Discord => p.DiscordConfiguration ?? new object(),
|
|
_ => new object()
|
|
}
|
|
})
|
|
.OrderBy(x => x.Type.ToString())
|
|
.ThenBy(x => x.Name)
|
|
.ToList();
|
|
|
|
var response = new NotificationProvidersResponse { Providers = providerDtos };
|
|
return Ok(response);
|
|
}
|
|
finally
|
|
{
|
|
DataContext.Lock.Release();
|
|
}
|
|
}
|
|
|
|
[HttpGet("apprise/cli-status")]
|
|
public async Task<IActionResult> GetAppriseCliStatus()
|
|
{
|
|
string? version = await _appriseCliDetector.GetAppriseVersionAsync();
|
|
|
|
return Ok(new
|
|
{
|
|
Available = version is not null,
|
|
Version = version
|
|
});
|
|
}
|
|
|
|
[HttpPost("notifiarr")]
|
|
public async Task<IActionResult> CreateNotifiarrProvider([FromBody] CreateNotifiarrProviderRequest newProvider)
|
|
{
|
|
await DataContext.Lock.WaitAsync();
|
|
try
|
|
{
|
|
if (string.IsNullOrWhiteSpace(newProvider.Name))
|
|
{
|
|
return BadRequest("Provider name is required");
|
|
}
|
|
|
|
var duplicateConfig = await _dataContext.NotificationConfigs.CountAsync(x => x.Name == newProvider.Name);
|
|
if (duplicateConfig > 0)
|
|
{
|
|
return BadRequest("A provider with this name already exists");
|
|
}
|
|
|
|
var notifiarrConfig = new NotifiarrConfig
|
|
{
|
|
ApiKey = newProvider.ApiKey,
|
|
ChannelId = newProvider.ChannelId
|
|
};
|
|
notifiarrConfig.Validate();
|
|
|
|
var provider = new NotificationConfig
|
|
{
|
|
Name = newProvider.Name,
|
|
Type = NotificationProviderType.Notifiarr,
|
|
IsEnabled = newProvider.IsEnabled,
|
|
OnFailedImportStrike = newProvider.OnFailedImportStrike,
|
|
OnStalledStrike = newProvider.OnStalledStrike,
|
|
OnSlowStrike = newProvider.OnSlowStrike,
|
|
OnQueueItemDeleted = newProvider.OnQueueItemDeleted,
|
|
OnDownloadCleaned = newProvider.OnDownloadCleaned,
|
|
OnCategoryChanged = newProvider.OnCategoryChanged,
|
|
NotifiarrConfiguration = notifiarrConfig
|
|
};
|
|
|
|
_dataContext.NotificationConfigs.Add(provider);
|
|
await _dataContext.SaveChangesAsync();
|
|
|
|
await _notificationConfigurationService.InvalidateCacheAsync();
|
|
|
|
var providerDto = MapProvider(provider);
|
|
return CreatedAtAction(nameof(GetNotificationProviders), new { id = provider.Id }, providerDto);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to create Notifiarr provider");
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
DataContext.Lock.Release();
|
|
}
|
|
}
|
|
|
|
[HttpPost("apprise")]
|
|
public async Task<IActionResult> CreateAppriseProvider([FromBody] CreateAppriseProviderRequest newProvider)
|
|
{
|
|
await DataContext.Lock.WaitAsync();
|
|
try
|
|
{
|
|
if (string.IsNullOrWhiteSpace(newProvider.Name))
|
|
{
|
|
return BadRequest("Provider name is required");
|
|
}
|
|
|
|
var duplicateConfig = await _dataContext.NotificationConfigs.CountAsync(x => x.Name == newProvider.Name);
|
|
if (duplicateConfig > 0)
|
|
{
|
|
return BadRequest("A provider with this name already exists");
|
|
}
|
|
|
|
var appriseConfig = new AppriseConfig
|
|
{
|
|
Mode = newProvider.Mode,
|
|
Url = newProvider.Url,
|
|
Key = newProvider.Key,
|
|
Tags = newProvider.Tags,
|
|
ServiceUrls = newProvider.ServiceUrls
|
|
};
|
|
appriseConfig.Validate();
|
|
|
|
var provider = new NotificationConfig
|
|
{
|
|
Name = newProvider.Name,
|
|
Type = NotificationProviderType.Apprise,
|
|
IsEnabled = newProvider.IsEnabled,
|
|
OnFailedImportStrike = newProvider.OnFailedImportStrike,
|
|
OnStalledStrike = newProvider.OnStalledStrike,
|
|
OnSlowStrike = newProvider.OnSlowStrike,
|
|
OnQueueItemDeleted = newProvider.OnQueueItemDeleted,
|
|
OnDownloadCleaned = newProvider.OnDownloadCleaned,
|
|
OnCategoryChanged = newProvider.OnCategoryChanged,
|
|
AppriseConfiguration = appriseConfig
|
|
};
|
|
|
|
_dataContext.NotificationConfigs.Add(provider);
|
|
await _dataContext.SaveChangesAsync();
|
|
|
|
await _notificationConfigurationService.InvalidateCacheAsync();
|
|
|
|
var providerDto = MapProvider(provider);
|
|
return CreatedAtAction(nameof(GetNotificationProviders), new { id = provider.Id }, providerDto);
|
|
}
|
|
catch (ValidationException ex)
|
|
{
|
|
return BadRequest(ex.Message);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to create Apprise provider");
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
DataContext.Lock.Release();
|
|
}
|
|
}
|
|
|
|
[HttpPost("ntfy")]
|
|
public async Task<IActionResult> CreateNtfyProvider([FromBody] CreateNtfyProviderRequest newProvider)
|
|
{
|
|
await DataContext.Lock.WaitAsync();
|
|
try
|
|
{
|
|
if (string.IsNullOrWhiteSpace(newProvider.Name))
|
|
{
|
|
return BadRequest("Provider name is required");
|
|
}
|
|
|
|
var duplicateConfig = await _dataContext.NotificationConfigs.CountAsync(x => x.Name == newProvider.Name);
|
|
if (duplicateConfig > 0)
|
|
{
|
|
return BadRequest("A provider with this name already exists");
|
|
}
|
|
|
|
var ntfyConfig = new NtfyConfig
|
|
{
|
|
ServerUrl = newProvider.ServerUrl,
|
|
Topics = newProvider.Topics,
|
|
AuthenticationType = newProvider.AuthenticationType,
|
|
Username = newProvider.Username,
|
|
Password = newProvider.Password,
|
|
AccessToken = newProvider.AccessToken,
|
|
Priority = newProvider.Priority,
|
|
Tags = newProvider.Tags
|
|
};
|
|
ntfyConfig.Validate();
|
|
|
|
var provider = new NotificationConfig
|
|
{
|
|
Name = newProvider.Name,
|
|
Type = NotificationProviderType.Ntfy,
|
|
IsEnabled = newProvider.IsEnabled,
|
|
OnFailedImportStrike = newProvider.OnFailedImportStrike,
|
|
OnStalledStrike = newProvider.OnStalledStrike,
|
|
OnSlowStrike = newProvider.OnSlowStrike,
|
|
OnQueueItemDeleted = newProvider.OnQueueItemDeleted,
|
|
OnDownloadCleaned = newProvider.OnDownloadCleaned,
|
|
OnCategoryChanged = newProvider.OnCategoryChanged,
|
|
NtfyConfiguration = ntfyConfig
|
|
};
|
|
|
|
_dataContext.NotificationConfigs.Add(provider);
|
|
await _dataContext.SaveChangesAsync();
|
|
|
|
await _notificationConfigurationService.InvalidateCacheAsync();
|
|
|
|
var providerDto = MapProvider(provider);
|
|
return CreatedAtAction(nameof(GetNotificationProviders), new { id = provider.Id }, providerDto);
|
|
}
|
|
catch (ValidationException ex)
|
|
{
|
|
return BadRequest(ex.Message);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to create Ntfy provider");
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
DataContext.Lock.Release();
|
|
}
|
|
}
|
|
|
|
[HttpPost("telegram")]
|
|
public async Task<IActionResult> CreateTelegramProvider([FromBody] CreateTelegramProviderRequest newProvider)
|
|
{
|
|
await DataContext.Lock.WaitAsync();
|
|
try
|
|
{
|
|
if (string.IsNullOrWhiteSpace(newProvider.Name))
|
|
{
|
|
return BadRequest("Provider name is required");
|
|
}
|
|
|
|
var duplicateConfig = await _dataContext.NotificationConfigs.CountAsync(x => x.Name == newProvider.Name);
|
|
if (duplicateConfig > 0)
|
|
{
|
|
return BadRequest("A provider with this name already exists");
|
|
}
|
|
|
|
var telegramConfig = new TelegramConfig
|
|
{
|
|
BotToken = newProvider.BotToken,
|
|
ChatId = newProvider.ChatId,
|
|
TopicId = newProvider.TopicId,
|
|
SendSilently = newProvider.SendSilently
|
|
};
|
|
telegramConfig.Validate();
|
|
|
|
var provider = new NotificationConfig
|
|
{
|
|
Name = newProvider.Name,
|
|
Type = NotificationProviderType.Telegram,
|
|
IsEnabled = newProvider.IsEnabled,
|
|
OnFailedImportStrike = newProvider.OnFailedImportStrike,
|
|
OnStalledStrike = newProvider.OnStalledStrike,
|
|
OnSlowStrike = newProvider.OnSlowStrike,
|
|
OnQueueItemDeleted = newProvider.OnQueueItemDeleted,
|
|
OnDownloadCleaned = newProvider.OnDownloadCleaned,
|
|
OnCategoryChanged = newProvider.OnCategoryChanged,
|
|
TelegramConfiguration = telegramConfig
|
|
};
|
|
|
|
_dataContext.NotificationConfigs.Add(provider);
|
|
await _dataContext.SaveChangesAsync();
|
|
|
|
await _notificationConfigurationService.InvalidateCacheAsync();
|
|
|
|
var providerDto = MapProvider(provider);
|
|
return CreatedAtAction(nameof(GetNotificationProviders), new { id = provider.Id }, providerDto);
|
|
}
|
|
catch (ValidationException ex)
|
|
{
|
|
return BadRequest(ex.Message);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to create Telegram provider");
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
DataContext.Lock.Release();
|
|
}
|
|
}
|
|
|
|
[HttpPut("notifiarr/{id:guid}")]
|
|
public async Task<IActionResult> UpdateNotifiarrProvider(Guid id, [FromBody] UpdateNotifiarrProviderRequest updatedProvider)
|
|
{
|
|
await DataContext.Lock.WaitAsync();
|
|
try
|
|
{
|
|
var existingProvider = await _dataContext.NotificationConfigs
|
|
.Include(p => p.NotifiarrConfiguration)
|
|
.FirstOrDefaultAsync(p => p.Id == id && p.Type == NotificationProviderType.Notifiarr);
|
|
|
|
if (existingProvider == null)
|
|
{
|
|
return NotFound($"Notifiarr provider with ID {id} not found");
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(updatedProvider.Name))
|
|
{
|
|
return BadRequest("Provider name is required");
|
|
}
|
|
|
|
var duplicateConfig = await _dataContext.NotificationConfigs
|
|
.Where(x => x.Id != id)
|
|
.Where(x => x.Name == updatedProvider.Name)
|
|
.CountAsync();
|
|
if (duplicateConfig > 0)
|
|
{
|
|
return BadRequest("A provider with this name already exists");
|
|
}
|
|
|
|
var notifiarrConfig = new NotifiarrConfig
|
|
{
|
|
ApiKey = updatedProvider.ApiKey,
|
|
ChannelId = updatedProvider.ChannelId
|
|
};
|
|
|
|
if (existingProvider.NotifiarrConfiguration != null)
|
|
{
|
|
notifiarrConfig = notifiarrConfig with { Id = existingProvider.NotifiarrConfiguration.Id };
|
|
}
|
|
notifiarrConfig.Validate();
|
|
|
|
var newProvider = existingProvider with
|
|
{
|
|
Name = updatedProvider.Name,
|
|
IsEnabled = updatedProvider.IsEnabled,
|
|
OnFailedImportStrike = updatedProvider.OnFailedImportStrike,
|
|
OnStalledStrike = updatedProvider.OnStalledStrike,
|
|
OnSlowStrike = updatedProvider.OnSlowStrike,
|
|
OnQueueItemDeleted = updatedProvider.OnQueueItemDeleted,
|
|
OnDownloadCleaned = updatedProvider.OnDownloadCleaned,
|
|
OnCategoryChanged = updatedProvider.OnCategoryChanged,
|
|
NotifiarrConfiguration = notifiarrConfig,
|
|
UpdatedAt = DateTime.UtcNow
|
|
};
|
|
|
|
_dataContext.NotificationConfigs.Remove(existingProvider);
|
|
_dataContext.NotificationConfigs.Add(newProvider);
|
|
|
|
await _dataContext.SaveChangesAsync();
|
|
await _notificationConfigurationService.InvalidateCacheAsync();
|
|
|
|
var providerDto = MapProvider(newProvider);
|
|
return Ok(providerDto);
|
|
}
|
|
catch (ValidationException ex)
|
|
{
|
|
return BadRequest(ex.Message);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to update Notifiarr provider with ID {Id}", id);
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
DataContext.Lock.Release();
|
|
}
|
|
}
|
|
|
|
[HttpPut("apprise/{id:guid}")]
|
|
public async Task<IActionResult> UpdateAppriseProvider(Guid id, [FromBody] UpdateAppriseProviderRequest updatedProvider)
|
|
{
|
|
await DataContext.Lock.WaitAsync();
|
|
try
|
|
{
|
|
var existingProvider = await _dataContext.NotificationConfigs
|
|
.Include(p => p.AppriseConfiguration)
|
|
.FirstOrDefaultAsync(p => p.Id == id && p.Type == NotificationProviderType.Apprise);
|
|
|
|
if (existingProvider == null)
|
|
{
|
|
return NotFound($"Apprise provider with ID {id} not found");
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(updatedProvider.Name))
|
|
{
|
|
return BadRequest("Provider name is required");
|
|
}
|
|
|
|
var duplicateConfig = await _dataContext.NotificationConfigs
|
|
.Where(x => x.Id != id)
|
|
.Where(x => x.Name == updatedProvider.Name)
|
|
.CountAsync();
|
|
if (duplicateConfig > 0)
|
|
{
|
|
return BadRequest("A provider with this name already exists");
|
|
}
|
|
|
|
var appriseConfig = new AppriseConfig
|
|
{
|
|
Mode = updatedProvider.Mode,
|
|
Url = updatedProvider.Url,
|
|
Key = updatedProvider.Key,
|
|
Tags = updatedProvider.Tags,
|
|
ServiceUrls = updatedProvider.ServiceUrls
|
|
};
|
|
|
|
if (existingProvider.AppriseConfiguration != null)
|
|
{
|
|
appriseConfig = appriseConfig with { Id = existingProvider.AppriseConfiguration.Id };
|
|
}
|
|
appriseConfig.Validate();
|
|
|
|
var newProvider = existingProvider with
|
|
{
|
|
Name = updatedProvider.Name,
|
|
IsEnabled = updatedProvider.IsEnabled,
|
|
OnFailedImportStrike = updatedProvider.OnFailedImportStrike,
|
|
OnStalledStrike = updatedProvider.OnStalledStrike,
|
|
OnSlowStrike = updatedProvider.OnSlowStrike,
|
|
OnQueueItemDeleted = updatedProvider.OnQueueItemDeleted,
|
|
OnDownloadCleaned = updatedProvider.OnDownloadCleaned,
|
|
OnCategoryChanged = updatedProvider.OnCategoryChanged,
|
|
AppriseConfiguration = appriseConfig,
|
|
UpdatedAt = DateTime.UtcNow
|
|
};
|
|
|
|
_dataContext.NotificationConfigs.Remove(existingProvider);
|
|
_dataContext.NotificationConfigs.Add(newProvider);
|
|
|
|
await _dataContext.SaveChangesAsync();
|
|
await _notificationConfigurationService.InvalidateCacheAsync();
|
|
|
|
var providerDto = MapProvider(newProvider);
|
|
return Ok(providerDto);
|
|
}
|
|
catch (ValidationException ex)
|
|
{
|
|
return BadRequest(ex.Message);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to update Apprise provider with ID {Id}", id);
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
DataContext.Lock.Release();
|
|
}
|
|
}
|
|
|
|
[HttpPut("ntfy/{id:guid}")]
|
|
public async Task<IActionResult> UpdateNtfyProvider(Guid id, [FromBody] UpdateNtfyProviderRequest updatedProvider)
|
|
{
|
|
await DataContext.Lock.WaitAsync();
|
|
try
|
|
{
|
|
var existingProvider = await _dataContext.NotificationConfigs
|
|
.Include(p => p.NtfyConfiguration)
|
|
.FirstOrDefaultAsync(p => p.Id == id && p.Type == NotificationProviderType.Ntfy);
|
|
|
|
if (existingProvider == null)
|
|
{
|
|
return NotFound($"Ntfy provider with ID {id} not found");
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(updatedProvider.Name))
|
|
{
|
|
return BadRequest("Provider name is required");
|
|
}
|
|
|
|
var duplicateConfig = await _dataContext.NotificationConfigs
|
|
.Where(x => x.Id != id)
|
|
.Where(x => x.Name == updatedProvider.Name)
|
|
.CountAsync();
|
|
if (duplicateConfig > 0)
|
|
{
|
|
return BadRequest("A provider with this name already exists");
|
|
}
|
|
|
|
var ntfyConfig = new NtfyConfig
|
|
{
|
|
ServerUrl = updatedProvider.ServerUrl,
|
|
Topics = updatedProvider.Topics,
|
|
AuthenticationType = updatedProvider.AuthenticationType,
|
|
Username = updatedProvider.Username,
|
|
Password = updatedProvider.Password,
|
|
AccessToken = updatedProvider.AccessToken,
|
|
Priority = updatedProvider.Priority,
|
|
Tags = updatedProvider.Tags
|
|
};
|
|
|
|
if (existingProvider.NtfyConfiguration != null)
|
|
{
|
|
ntfyConfig = ntfyConfig with { Id = existingProvider.NtfyConfiguration.Id };
|
|
}
|
|
ntfyConfig.Validate();
|
|
|
|
var newProvider = existingProvider with
|
|
{
|
|
Name = updatedProvider.Name,
|
|
IsEnabled = updatedProvider.IsEnabled,
|
|
OnFailedImportStrike = updatedProvider.OnFailedImportStrike,
|
|
OnStalledStrike = updatedProvider.OnStalledStrike,
|
|
OnSlowStrike = updatedProvider.OnSlowStrike,
|
|
OnQueueItemDeleted = updatedProvider.OnQueueItemDeleted,
|
|
OnDownloadCleaned = updatedProvider.OnDownloadCleaned,
|
|
OnCategoryChanged = updatedProvider.OnCategoryChanged,
|
|
NtfyConfiguration = ntfyConfig,
|
|
UpdatedAt = DateTime.UtcNow
|
|
};
|
|
|
|
_dataContext.NotificationConfigs.Remove(existingProvider);
|
|
_dataContext.NotificationConfigs.Add(newProvider);
|
|
|
|
await _dataContext.SaveChangesAsync();
|
|
await _notificationConfigurationService.InvalidateCacheAsync();
|
|
|
|
var providerDto = MapProvider(newProvider);
|
|
return Ok(providerDto);
|
|
}
|
|
catch (ValidationException ex)
|
|
{
|
|
return BadRequest(ex.Message);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to update Ntfy provider with ID {Id}", id);
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
DataContext.Lock.Release();
|
|
}
|
|
}
|
|
|
|
[HttpPut("telegram/{id:guid}")]
|
|
public async Task<IActionResult> UpdateTelegramProvider(Guid id, [FromBody] UpdateTelegramProviderRequest updatedProvider)
|
|
{
|
|
await DataContext.Lock.WaitAsync();
|
|
try
|
|
{
|
|
var existingProvider = await _dataContext.NotificationConfigs
|
|
.Include(p => p.TelegramConfiguration)
|
|
.FirstOrDefaultAsync(p => p.Id == id && p.Type == NotificationProviderType.Telegram);
|
|
|
|
if (existingProvider == null)
|
|
{
|
|
return NotFound($"Telegram provider with ID {id} not found");
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(updatedProvider.Name))
|
|
{
|
|
return BadRequest("Provider name is required");
|
|
}
|
|
|
|
var duplicateConfig = await _dataContext.NotificationConfigs
|
|
.Where(x => x.Id != id)
|
|
.Where(x => x.Name == updatedProvider.Name)
|
|
.CountAsync();
|
|
if (duplicateConfig > 0)
|
|
{
|
|
return BadRequest("A provider with this name already exists");
|
|
}
|
|
|
|
var telegramConfig = new TelegramConfig
|
|
{
|
|
BotToken = updatedProvider.BotToken,
|
|
ChatId = updatedProvider.ChatId,
|
|
TopicId = updatedProvider.TopicId,
|
|
SendSilently = updatedProvider.SendSilently
|
|
};
|
|
|
|
if (existingProvider.TelegramConfiguration != null)
|
|
{
|
|
telegramConfig = telegramConfig with { Id = existingProvider.TelegramConfiguration.Id };
|
|
}
|
|
telegramConfig.Validate();
|
|
|
|
var newProvider = existingProvider with
|
|
{
|
|
Name = updatedProvider.Name,
|
|
IsEnabled = updatedProvider.IsEnabled,
|
|
OnFailedImportStrike = updatedProvider.OnFailedImportStrike,
|
|
OnStalledStrike = updatedProvider.OnStalledStrike,
|
|
OnSlowStrike = updatedProvider.OnSlowStrike,
|
|
OnQueueItemDeleted = updatedProvider.OnQueueItemDeleted,
|
|
OnDownloadCleaned = updatedProvider.OnDownloadCleaned,
|
|
OnCategoryChanged = updatedProvider.OnCategoryChanged,
|
|
TelegramConfiguration = telegramConfig,
|
|
UpdatedAt = DateTime.UtcNow
|
|
};
|
|
|
|
_dataContext.NotificationConfigs.Remove(existingProvider);
|
|
_dataContext.NotificationConfigs.Add(newProvider);
|
|
|
|
await _dataContext.SaveChangesAsync();
|
|
await _notificationConfigurationService.InvalidateCacheAsync();
|
|
|
|
var providerDto = MapProvider(newProvider);
|
|
return Ok(providerDto);
|
|
}
|
|
catch (ValidationException ex)
|
|
{
|
|
return BadRequest(ex.Message);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to update Telegram provider with ID {Id}", id);
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
DataContext.Lock.Release();
|
|
}
|
|
}
|
|
|
|
[HttpDelete("{id:guid}")]
|
|
public async Task<IActionResult> DeleteNotificationProvider(Guid id)
|
|
{
|
|
await DataContext.Lock.WaitAsync();
|
|
try
|
|
{
|
|
var existingProvider = await _dataContext.NotificationConfigs
|
|
.Include(p => p.NotifiarrConfiguration)
|
|
.Include(p => p.AppriseConfiguration)
|
|
.Include(p => p.NtfyConfiguration)
|
|
.Include(p => p.PushoverConfiguration)
|
|
.Include(p => p.TelegramConfiguration)
|
|
.Include(p => p.DiscordConfiguration)
|
|
.FirstOrDefaultAsync(p => p.Id == id);
|
|
|
|
if (existingProvider == null)
|
|
{
|
|
return NotFound($"Notification provider with ID {id} not found");
|
|
}
|
|
|
|
_dataContext.NotificationConfigs.Remove(existingProvider);
|
|
await _dataContext.SaveChangesAsync();
|
|
|
|
await _notificationConfigurationService.InvalidateCacheAsync();
|
|
|
|
_logger.LogInformation("Removed notification provider {ProviderName} with ID {ProviderId}",
|
|
existingProvider.Name, existingProvider.Id);
|
|
|
|
return NoContent();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to delete notification provider with ID {Id}", id);
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
DataContext.Lock.Release();
|
|
}
|
|
}
|
|
|
|
[HttpPost("notifiarr/test")]
|
|
public async Task<IActionResult> TestNotifiarrProvider([FromBody] TestNotifiarrProviderRequest testRequest)
|
|
{
|
|
try
|
|
{
|
|
var notifiarrConfig = new NotifiarrConfig
|
|
{
|
|
ApiKey = testRequest.ApiKey,
|
|
ChannelId = testRequest.ChannelId
|
|
};
|
|
notifiarrConfig.Validate();
|
|
|
|
var providerDto = new NotificationProviderDto
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Name = "Test Provider",
|
|
Type = NotificationProviderType.Notifiarr,
|
|
IsEnabled = true,
|
|
Events = new NotificationEventFlags
|
|
{
|
|
OnFailedImportStrike = true,
|
|
OnStalledStrike = false,
|
|
OnSlowStrike = false,
|
|
OnQueueItemDeleted = false,
|
|
OnDownloadCleaned = false,
|
|
OnCategoryChanged = false
|
|
},
|
|
Configuration = notifiarrConfig
|
|
};
|
|
|
|
await _notificationService.SendTestNotificationAsync(providerDto);
|
|
return Ok(new { Message = "Test notification sent successfully" });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to test Notifiarr provider");
|
|
return BadRequest(new { Message = $"Test failed: {ex.Message}" });
|
|
}
|
|
}
|
|
|
|
[HttpPost("apprise/test")]
|
|
public async Task<IActionResult> TestAppriseProvider([FromBody] TestAppriseProviderRequest testRequest)
|
|
{
|
|
try
|
|
{
|
|
var appriseConfig = new AppriseConfig
|
|
{
|
|
Mode = testRequest.Mode,
|
|
Url = testRequest.Url,
|
|
Key = testRequest.Key,
|
|
Tags = testRequest.Tags,
|
|
ServiceUrls = testRequest.ServiceUrls
|
|
};
|
|
appriseConfig.Validate();
|
|
|
|
var providerDto = new NotificationProviderDto
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Name = "Test Provider",
|
|
Type = NotificationProviderType.Apprise,
|
|
IsEnabled = true,
|
|
Events = new NotificationEventFlags
|
|
{
|
|
OnFailedImportStrike = true,
|
|
OnStalledStrike = false,
|
|
OnSlowStrike = false,
|
|
OnQueueItemDeleted = false,
|
|
OnDownloadCleaned = false,
|
|
OnCategoryChanged = false
|
|
},
|
|
Configuration = appriseConfig
|
|
};
|
|
|
|
await _notificationService.SendTestNotificationAsync(providerDto);
|
|
return Ok(new { Message = "Test notification sent successfully" });
|
|
}
|
|
catch (AppriseException exception)
|
|
{
|
|
return StatusCode((int)HttpStatusCode.InternalServerError, exception.Message);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to test Apprise provider");
|
|
return BadRequest(new { Message = $"Test failed: {ex.Message}" });
|
|
}
|
|
}
|
|
|
|
[HttpPost("ntfy/test")]
|
|
public async Task<IActionResult> TestNtfyProvider([FromBody] TestNtfyProviderRequest testRequest)
|
|
{
|
|
try
|
|
{
|
|
var ntfyConfig = new NtfyConfig
|
|
{
|
|
ServerUrl = testRequest.ServerUrl,
|
|
Topics = testRequest.Topics,
|
|
AuthenticationType = testRequest.AuthenticationType,
|
|
Username = testRequest.Username,
|
|
Password = testRequest.Password,
|
|
AccessToken = testRequest.AccessToken,
|
|
Priority = testRequest.Priority,
|
|
Tags = testRequest.Tags
|
|
};
|
|
ntfyConfig.Validate();
|
|
|
|
var providerDto = new NotificationProviderDto
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Name = "Test Provider",
|
|
Type = NotificationProviderType.Ntfy,
|
|
IsEnabled = true,
|
|
Events = new NotificationEventFlags
|
|
{
|
|
OnFailedImportStrike = true,
|
|
OnStalledStrike = false,
|
|
OnSlowStrike = false,
|
|
OnQueueItemDeleted = false,
|
|
OnDownloadCleaned = false,
|
|
OnCategoryChanged = false
|
|
},
|
|
Configuration = ntfyConfig
|
|
};
|
|
|
|
await _notificationService.SendTestNotificationAsync(providerDto);
|
|
return Ok(new { Message = "Test notification sent successfully" });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to test Ntfy provider");
|
|
return BadRequest(new { Message = $"Test failed: {ex.Message}" });
|
|
}
|
|
}
|
|
|
|
[HttpPost("telegram/test")]
|
|
public async Task<IActionResult> TestTelegramProvider([FromBody] TestTelegramProviderRequest testRequest)
|
|
{
|
|
try
|
|
{
|
|
var telegramConfig = new TelegramConfig
|
|
{
|
|
BotToken = testRequest.BotToken,
|
|
ChatId = testRequest.ChatId,
|
|
TopicId = testRequest.TopicId,
|
|
SendSilently = testRequest.SendSilently
|
|
};
|
|
telegramConfig.Validate();
|
|
|
|
var providerDto = new NotificationProviderDto
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Name = "Test Provider",
|
|
Type = NotificationProviderType.Telegram,
|
|
IsEnabled = true,
|
|
Events = new NotificationEventFlags
|
|
{
|
|
OnFailedImportStrike = true,
|
|
OnStalledStrike = false,
|
|
OnSlowStrike = false,
|
|
OnQueueItemDeleted = false,
|
|
OnDownloadCleaned = false,
|
|
OnCategoryChanged = false
|
|
},
|
|
Configuration = telegramConfig
|
|
};
|
|
|
|
await _notificationService.SendTestNotificationAsync(providerDto);
|
|
return Ok(new { Message = "Test notification sent successfully" });
|
|
}
|
|
catch (TelegramException ex)
|
|
{
|
|
_logger.LogWarning(ex, "Failed to test Telegram provider");
|
|
return BadRequest(new { Message = $"Test failed: {ex.Message}" });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to test Telegram provider");
|
|
return BadRequest(new { Message = $"Test failed: {ex.Message}" });
|
|
}
|
|
}
|
|
|
|
private static NotificationProviderResponse MapProvider(NotificationConfig provider)
|
|
{
|
|
return new NotificationProviderResponse
|
|
{
|
|
Id = provider.Id,
|
|
Name = provider.Name,
|
|
Type = provider.Type,
|
|
IsEnabled = provider.IsEnabled,
|
|
Events = new NotificationEventFlags
|
|
{
|
|
OnFailedImportStrike = provider.OnFailedImportStrike,
|
|
OnStalledStrike = provider.OnStalledStrike,
|
|
OnSlowStrike = provider.OnSlowStrike,
|
|
OnQueueItemDeleted = provider.OnQueueItemDeleted,
|
|
OnDownloadCleaned = provider.OnDownloadCleaned,
|
|
OnCategoryChanged = provider.OnCategoryChanged
|
|
},
|
|
Configuration = provider.Type switch
|
|
{
|
|
NotificationProviderType.Notifiarr => provider.NotifiarrConfiguration ?? new object(),
|
|
NotificationProviderType.Apprise => provider.AppriseConfiguration ?? new object(),
|
|
NotificationProviderType.Ntfy => provider.NtfyConfiguration ?? new object(),
|
|
NotificationProviderType.Pushover => provider.PushoverConfiguration ?? new object(),
|
|
NotificationProviderType.Telegram => provider.TelegramConfiguration ?? new object(),
|
|
NotificationProviderType.Discord => provider.DiscordConfiguration ?? new object(),
|
|
_ => new object()
|
|
}
|
|
};
|
|
}
|
|
|
|
[HttpPost("discord")]
|
|
public async Task<IActionResult> CreateDiscordProvider([FromBody] CreateDiscordProviderRequest newProvider)
|
|
{
|
|
await DataContext.Lock.WaitAsync();
|
|
try
|
|
{
|
|
if (string.IsNullOrWhiteSpace(newProvider.Name))
|
|
{
|
|
return BadRequest("Provider name is required");
|
|
}
|
|
|
|
var duplicateConfig = await _dataContext.NotificationConfigs.CountAsync(x => x.Name == newProvider.Name);
|
|
if (duplicateConfig > 0)
|
|
{
|
|
return BadRequest("A provider with this name already exists");
|
|
}
|
|
|
|
var discordConfig = new DiscordConfig
|
|
{
|
|
WebhookUrl = newProvider.WebhookUrl,
|
|
Username = newProvider.Username,
|
|
AvatarUrl = newProvider.AvatarUrl
|
|
};
|
|
discordConfig.Validate();
|
|
|
|
var provider = new NotificationConfig
|
|
{
|
|
Name = newProvider.Name,
|
|
Type = NotificationProviderType.Discord,
|
|
IsEnabled = newProvider.IsEnabled,
|
|
OnFailedImportStrike = newProvider.OnFailedImportStrike,
|
|
OnStalledStrike = newProvider.OnStalledStrike,
|
|
OnSlowStrike = newProvider.OnSlowStrike,
|
|
OnQueueItemDeleted = newProvider.OnQueueItemDeleted,
|
|
OnDownloadCleaned = newProvider.OnDownloadCleaned,
|
|
OnCategoryChanged = newProvider.OnCategoryChanged,
|
|
DiscordConfiguration = discordConfig
|
|
};
|
|
|
|
_dataContext.NotificationConfigs.Add(provider);
|
|
await _dataContext.SaveChangesAsync();
|
|
|
|
await _notificationConfigurationService.InvalidateCacheAsync();
|
|
|
|
var providerDto = MapProvider(provider);
|
|
return CreatedAtAction(nameof(GetNotificationProviders), new { id = provider.Id }, providerDto);
|
|
}
|
|
catch (ValidationException ex)
|
|
{
|
|
return BadRequest(ex.Message);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to create Discord provider");
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
DataContext.Lock.Release();
|
|
}
|
|
}
|
|
|
|
[HttpPut("discord/{id:guid}")]
|
|
public async Task<IActionResult> UpdateDiscordProvider(Guid id, [FromBody] UpdateDiscordProviderRequest updatedProvider)
|
|
{
|
|
await DataContext.Lock.WaitAsync();
|
|
try
|
|
{
|
|
var existingProvider = await _dataContext.NotificationConfigs
|
|
.Include(p => p.DiscordConfiguration)
|
|
.FirstOrDefaultAsync(p => p.Id == id && p.Type == NotificationProviderType.Discord);
|
|
|
|
if (existingProvider == null)
|
|
{
|
|
return NotFound($"Discord provider with ID {id} not found");
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(updatedProvider.Name))
|
|
{
|
|
return BadRequest("Provider name is required");
|
|
}
|
|
|
|
var duplicateConfig = await _dataContext.NotificationConfigs
|
|
.Where(x => x.Id != id)
|
|
.Where(x => x.Name == updatedProvider.Name)
|
|
.CountAsync();
|
|
if (duplicateConfig > 0)
|
|
{
|
|
return BadRequest("A provider with this name already exists");
|
|
}
|
|
|
|
var discordConfig = new DiscordConfig
|
|
{
|
|
WebhookUrl = updatedProvider.WebhookUrl,
|
|
Username = updatedProvider.Username,
|
|
AvatarUrl = updatedProvider.AvatarUrl
|
|
};
|
|
|
|
if (existingProvider.DiscordConfiguration != null)
|
|
{
|
|
discordConfig = discordConfig with { Id = existingProvider.DiscordConfiguration.Id };
|
|
}
|
|
discordConfig.Validate();
|
|
|
|
var newProvider = existingProvider with
|
|
{
|
|
Name = updatedProvider.Name,
|
|
IsEnabled = updatedProvider.IsEnabled,
|
|
OnFailedImportStrike = updatedProvider.OnFailedImportStrike,
|
|
OnStalledStrike = updatedProvider.OnStalledStrike,
|
|
OnSlowStrike = updatedProvider.OnSlowStrike,
|
|
OnQueueItemDeleted = updatedProvider.OnQueueItemDeleted,
|
|
OnDownloadCleaned = updatedProvider.OnDownloadCleaned,
|
|
OnCategoryChanged = updatedProvider.OnCategoryChanged,
|
|
DiscordConfiguration = discordConfig,
|
|
UpdatedAt = DateTime.UtcNow
|
|
};
|
|
|
|
_dataContext.NotificationConfigs.Remove(existingProvider);
|
|
_dataContext.NotificationConfigs.Add(newProvider);
|
|
|
|
await _dataContext.SaveChangesAsync();
|
|
await _notificationConfigurationService.InvalidateCacheAsync();
|
|
|
|
var providerDto = MapProvider(newProvider);
|
|
return Ok(providerDto);
|
|
}
|
|
catch (ValidationException ex)
|
|
{
|
|
return BadRequest(ex.Message);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to update Discord provider with ID {Id}", id);
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
DataContext.Lock.Release();
|
|
}
|
|
}
|
|
|
|
[HttpPost("discord/test")]
|
|
public async Task<IActionResult> TestDiscordProvider([FromBody] TestDiscordProviderRequest testRequest)
|
|
{
|
|
try
|
|
{
|
|
var discordConfig = new DiscordConfig
|
|
{
|
|
WebhookUrl = testRequest.WebhookUrl,
|
|
Username = testRequest.Username,
|
|
AvatarUrl = testRequest.AvatarUrl
|
|
};
|
|
discordConfig.Validate();
|
|
|
|
var providerDto = new NotificationProviderDto
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Name = "Test Provider",
|
|
Type = NotificationProviderType.Discord,
|
|
IsEnabled = true,
|
|
Events = new NotificationEventFlags
|
|
{
|
|
OnFailedImportStrike = true,
|
|
OnStalledStrike = false,
|
|
OnSlowStrike = false,
|
|
OnQueueItemDeleted = false,
|
|
OnDownloadCleaned = false,
|
|
OnCategoryChanged = false
|
|
},
|
|
Configuration = discordConfig
|
|
};
|
|
|
|
await _notificationService.SendTestNotificationAsync(providerDto);
|
|
return Ok(new { Message = "Test notification sent successfully" });
|
|
}
|
|
catch (DiscordException ex)
|
|
{
|
|
_logger.LogWarning(ex, "Failed to test Discord provider");
|
|
return BadRequest(new { Message = $"Test failed: {ex.Message}" });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to test Discord provider");
|
|
return BadRequest(new { Message = $"Test failed: {ex.Message}" });
|
|
}
|
|
}
|
|
|
|
[HttpPost("pushover")]
|
|
public async Task<IActionResult> CreatePushoverProvider([FromBody] CreatePushoverProviderRequest newProvider)
|
|
{
|
|
await DataContext.Lock.WaitAsync();
|
|
try
|
|
{
|
|
if (string.IsNullOrWhiteSpace(newProvider.Name))
|
|
{
|
|
return BadRequest("Provider name is required");
|
|
}
|
|
|
|
var duplicateConfig = await _dataContext.NotificationConfigs.CountAsync(x => x.Name == newProvider.Name);
|
|
if (duplicateConfig > 0)
|
|
{
|
|
return BadRequest("A provider with this name already exists");
|
|
}
|
|
|
|
var pushoverConfig = new PushoverConfig
|
|
{
|
|
ApiToken = newProvider.ApiToken,
|
|
UserKey = newProvider.UserKey,
|
|
Devices = newProvider.Devices,
|
|
Priority = newProvider.Priority,
|
|
Sound = newProvider.Sound,
|
|
Retry = newProvider.Retry,
|
|
Expire = newProvider.Expire,
|
|
Tags = newProvider.Tags
|
|
};
|
|
pushoverConfig.Validate();
|
|
|
|
var provider = new NotificationConfig
|
|
{
|
|
Name = newProvider.Name,
|
|
Type = NotificationProviderType.Pushover,
|
|
IsEnabled = newProvider.IsEnabled,
|
|
OnFailedImportStrike = newProvider.OnFailedImportStrike,
|
|
OnStalledStrike = newProvider.OnStalledStrike,
|
|
OnSlowStrike = newProvider.OnSlowStrike,
|
|
OnQueueItemDeleted = newProvider.OnQueueItemDeleted,
|
|
OnDownloadCleaned = newProvider.OnDownloadCleaned,
|
|
OnCategoryChanged = newProvider.OnCategoryChanged,
|
|
PushoverConfiguration = pushoverConfig
|
|
};
|
|
|
|
_dataContext.NotificationConfigs.Add(provider);
|
|
await _dataContext.SaveChangesAsync();
|
|
|
|
await _notificationConfigurationService.InvalidateCacheAsync();
|
|
|
|
var providerDto = MapProvider(provider);
|
|
return CreatedAtAction(nameof(GetNotificationProviders), new { id = provider.Id }, providerDto);
|
|
}
|
|
catch (ValidationException ex)
|
|
{
|
|
return BadRequest(ex.Message);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to create Pushover provider");
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
DataContext.Lock.Release();
|
|
}
|
|
}
|
|
|
|
[HttpPut("pushover/{id:guid}")]
|
|
public async Task<IActionResult> UpdatePushoverProvider(Guid id, [FromBody] UpdatePushoverProviderRequest updatedProvider)
|
|
{
|
|
await DataContext.Lock.WaitAsync();
|
|
try
|
|
{
|
|
var existingProvider = await _dataContext.NotificationConfigs
|
|
.Include(p => p.PushoverConfiguration)
|
|
.FirstOrDefaultAsync(p => p.Id == id && p.Type == NotificationProviderType.Pushover);
|
|
|
|
if (existingProvider == null)
|
|
{
|
|
return NotFound($"Pushover provider with ID {id} not found");
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(updatedProvider.Name))
|
|
{
|
|
return BadRequest("Provider name is required");
|
|
}
|
|
|
|
var duplicateConfig = await _dataContext.NotificationConfigs
|
|
.Where(x => x.Id != id)
|
|
.Where(x => x.Name == updatedProvider.Name)
|
|
.CountAsync();
|
|
if (duplicateConfig > 0)
|
|
{
|
|
return BadRequest("A provider with this name already exists");
|
|
}
|
|
|
|
var pushoverConfig = new PushoverConfig
|
|
{
|
|
ApiToken = updatedProvider.ApiToken,
|
|
UserKey = updatedProvider.UserKey,
|
|
Devices = updatedProvider.Devices,
|
|
Priority = updatedProvider.Priority,
|
|
Sound = updatedProvider.Sound,
|
|
Retry = updatedProvider.Retry,
|
|
Expire = updatedProvider.Expire,
|
|
Tags = updatedProvider.Tags
|
|
};
|
|
|
|
if (existingProvider.PushoverConfiguration != null)
|
|
{
|
|
pushoverConfig = pushoverConfig with { Id = existingProvider.PushoverConfiguration.Id };
|
|
}
|
|
pushoverConfig.Validate();
|
|
|
|
var newProvider = existingProvider with
|
|
{
|
|
Name = updatedProvider.Name,
|
|
IsEnabled = updatedProvider.IsEnabled,
|
|
OnFailedImportStrike = updatedProvider.OnFailedImportStrike,
|
|
OnStalledStrike = updatedProvider.OnStalledStrike,
|
|
OnSlowStrike = updatedProvider.OnSlowStrike,
|
|
OnQueueItemDeleted = updatedProvider.OnQueueItemDeleted,
|
|
OnDownloadCleaned = updatedProvider.OnDownloadCleaned,
|
|
OnCategoryChanged = updatedProvider.OnCategoryChanged,
|
|
PushoverConfiguration = pushoverConfig,
|
|
UpdatedAt = DateTime.UtcNow
|
|
};
|
|
|
|
_dataContext.NotificationConfigs.Remove(existingProvider);
|
|
_dataContext.NotificationConfigs.Add(newProvider);
|
|
|
|
await _dataContext.SaveChangesAsync();
|
|
await _notificationConfigurationService.InvalidateCacheAsync();
|
|
|
|
var providerDto = MapProvider(newProvider);
|
|
return Ok(providerDto);
|
|
}
|
|
catch (ValidationException ex)
|
|
{
|
|
return BadRequest(ex.Message);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to update Pushover provider with ID {Id}", id);
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
DataContext.Lock.Release();
|
|
}
|
|
}
|
|
|
|
[HttpPost("pushover/test")]
|
|
public async Task<IActionResult> TestPushoverProvider([FromBody] TestPushoverProviderRequest testRequest)
|
|
{
|
|
try
|
|
{
|
|
var pushoverConfig = new PushoverConfig
|
|
{
|
|
ApiToken = testRequest.ApiToken,
|
|
UserKey = testRequest.UserKey,
|
|
Devices = testRequest.Devices,
|
|
Priority = testRequest.Priority,
|
|
Sound = testRequest.Sound,
|
|
Retry = testRequest.Retry,
|
|
Expire = testRequest.Expire,
|
|
Tags = testRequest.Tags
|
|
};
|
|
pushoverConfig.Validate();
|
|
|
|
var providerDto = new NotificationProviderDto
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Name = "Test Provider",
|
|
Type = NotificationProviderType.Pushover,
|
|
IsEnabled = true,
|
|
Events = new NotificationEventFlags
|
|
{
|
|
OnFailedImportStrike = true,
|
|
OnStalledStrike = false,
|
|
OnSlowStrike = false,
|
|
OnQueueItemDeleted = false,
|
|
OnDownloadCleaned = false,
|
|
OnCategoryChanged = false
|
|
},
|
|
Configuration = pushoverConfig
|
|
};
|
|
|
|
await _notificationService.SendTestNotificationAsync(providerDto);
|
|
return Ok(new { Message = "Test notification sent successfully" });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to test Pushover provider");
|
|
return BadRequest(new { Message = $"Test failed: {ex.Message}" });
|
|
}
|
|
}
|
|
}
|