using System; using System.Linq; using System.Security.Principal; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Ombi.Api.CouchPotato; using Ombi.Api.Emby; using Ombi.Api.Jellyfin; using Ombi.Api.Lidarr; using Ombi.Api.Plex; using Ombi.Api.Radarr; using Ombi.Api.SickRage; using Ombi.Api.Sonarr; using Ombi.Api.Twilio; using Ombi.Attributes; using Ombi.Core.Authentication; using Ombi.Core.Models; using Ombi.Core.Models.UI; using Ombi.Core.Notifications; using Ombi.Core.Settings.Models.External; using Ombi.Helpers; using Ombi.Models; using Ombi.Notifications; using Ombi.Notifications.Agents; using Ombi.Notifications.Models; using Ombi.Schedule.Jobs.Ombi; using Ombi.Settings.Settings.Models.External; using Ombi.Settings.Settings.Models.Notifications; using Ombi.Store.Entities; namespace Ombi.Controllers.V1.External { /// /// The Tester Controller /// [Admin] [ApiV1] [Produces("application/json")] public class TesterController : Controller { /// /// Initializes a new instance of the class. /// public TesterController(INotificationService service, IDiscordNotification notification, IEmailNotification emailN, IPushbulletNotification pushbullet, ISlackNotification slack, IPushoverNotification po, IMattermostNotification mm, IPlexApi plex, IEmbyApiFactory emby, IRadarrV3Api radarr, ISonarrV3Api sonarr, ILogger log, IEmailProvider provider, ICouchPotatoApi cpApi, ITelegramNotification telegram, ISickRageApi srApi, INewsletterJob newsletter, ILegacyMobileNotification mobileNotification, ILidarrApi lidarrApi, IGotifyNotification gotifyNotification, IWhatsAppApi whatsAppApi, OmbiUserManager um, IWebhookNotification webhookNotification, IJellyfinApi jellyfinApi, IPrincipal user) { Service = service; DiscordNotification = notification; EmailNotification = emailN; PushbulletNotification = pushbullet; SlackNotification = slack; PushoverNotification = po; MattermostNotification = mm; PlexApi = plex; RadarrApi = radarr; EmbyApi = emby; SonarrApi = sonarr; Log = log; EmailProvider = provider; CouchPotatoApi = cpApi; TelegramNotification = telegram; SickRageApi = srApi; Newsletter = newsletter; MobileNotification = mobileNotification; LidarrApi = lidarrApi; GotifyNotification = gotifyNotification; WhatsAppApi = whatsAppApi; UserManager = um; WebhookNotification = webhookNotification; _jellyfinApi = jellyfinApi; UserPrinciple = user; } private INotificationService Service { get; } private IDiscordNotification DiscordNotification { get; } private IEmailNotification EmailNotification { get; } private IPushbulletNotification PushbulletNotification { get; } private ISlackNotification SlackNotification { get; } private IPushoverNotification PushoverNotification { get; } private IGotifyNotification GotifyNotification { get; } private IWebhookNotification WebhookNotification { get; } private IMattermostNotification MattermostNotification { get; } private IPlexApi PlexApi { get; } private IRadarrV3Api RadarrApi { get; } private IEmbyApiFactory EmbyApi { get; } private ISonarrV3Api SonarrApi { get; } private ICouchPotatoApi CouchPotatoApi { get; } private ILogger Log { get; } private IEmailProvider EmailProvider { get; } private ITelegramNotification TelegramNotification { get; } private ISickRageApi SickRageApi { get; } private INewsletterJob Newsletter { get; } private ILegacyMobileNotification MobileNotification { get; } private ILidarrApi LidarrApi { get; } private IWhatsAppApi WhatsAppApi { get; } private OmbiUserManager UserManager {get; } private readonly IJellyfinApi _jellyfinApi; private IPrincipal UserPrinciple { get; } /// /// Sends a test message to discord using the provided settings /// /// The settings. /// [HttpPost("discord")] public async Task Discord([FromBody] DiscordNotificationSettings settings) { try { settings.Enabled = true; await DiscordNotification.NotifyAsync( new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); return true; } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test Discord"); return false; } } /// /// Sends a test message to Pushbullet using the provided settings /// /// The settings. /// [HttpPost("pushbullet")] public async Task Pushbullet([FromBody] PushbulletSettings settings) { try { settings.Enabled = true; await PushbulletNotification.NotifyAsync( new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); return true; } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test Pushbullet"); return false; } } /// /// Sends a test message to Pushover using the provided settings /// /// The settings. /// [HttpPost("pushover")] public async Task Pushover([FromBody] PushoverSettings settings) { try { settings.Enabled = true; await PushoverNotification.NotifyAsync( new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); return true; } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test Pushover"); return false; } } /// /// Sends a test message to Gotify using the provided settings /// /// The settings. /// [HttpPost("gotify")] public async Task Gotify([FromBody] GotifySettings settings) { try { settings.Enabled = true; await GotifyNotification.NotifyAsync( new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); return true; } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test Gotify"); return false; } } /// /// Sends a test message to configured webhook using the provided settings /// /// The settings. /// [HttpPost("webhook")] public async Task Webhook([FromBody] WebhookSettings settings) { try { settings.Enabled = true; await WebhookNotification.NotifyAsync( new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); return true; } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test your webhook"); return false; } } /// /// Sends a test message to mattermost using the provided settings /// /// The settings. /// [HttpPost("mattermost")] public async Task Mattermost([FromBody] MattermostNotificationSettings settings) { try { settings.Enabled = true; await MattermostNotification.NotifyAsync( new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); return true; } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test Mattermost"); return false; } } /// /// Sends a test message to Slack using the provided settings /// /// The settings. /// [HttpPost("slack")] public async Task Slack([FromBody] SlackNotificationSettings settings) { try { settings.Enabled = true; await SlackNotification.NotifyAsync( new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); return true; } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test Slack"); return false; } } /// /// Sends a test message via email to the admin email using the provided settings /// /// The settings. /// [HttpPost("email")] public async Task Email([FromBody] EmailNotificationSettings settings) { try { var currentUser = await GetCurrentUserAsync(); if (!currentUser.Email.HasValue()) { throw new Exception($"User '{currentUser.UserName}' has no email address set on their user profile."); } var message = new NotificationMessage { Message = "This is just a test! Success!", Subject = $"Ombi: Test", To = currentUser.Email, }; message.Other.Add("PlainTextBody", "This is just a test! Success!"); await EmailProvider.SendAdHoc(message, settings); } catch (Exception e) { Log.LogWarning(e, "Exception when testing Email Notifications"); return false; } return true; } private async Task GetCurrentUserAsync() { return await UserManager.Users.FirstOrDefaultAsync(x => x.NormalizedUserName == UserPrinciple.Identity.Name.ToUpper()); } /// /// Checks if we can connect to Plex with the provided settings /// /// /// [HttpPost("plex")] public async Task Plex([FromBody] PlexServers settings) { try { var result = await PlexApi.GetStatus(settings.PlexAuthToken, settings.FullUri); return result?.MediaContainer?.version != null; } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test Plex"); return false; } } /// /// Checks if we can connect to Emby with the provided settings /// /// /// [HttpPost("emby")] public async Task Emby([FromBody] EmbyServers settings) { try { var client = await EmbyApi.CreateClient(); var result = await client.GetUsers(settings.FullUri, settings.ApiKey); return result.Any(); } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test Emby"); return false; } } /// /// Checks if we can connect to Jellyfin with the provided settings /// /// /// [HttpPost("jellyfin")] public async Task Jellyfin([FromBody] JellyfinServers settings) { try { var result = await _jellyfinApi.GetUsers(settings.FullUri, settings.ApiKey); return result.Any(); } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test Jellyfin"); return false; } } /// /// Checks if we can connect to Radarr with the provided settings /// /// /// [HttpPost("radarr")] public async Task Radarr([FromBody] RadarrSettings settings) { try { var result = await RadarrApi.SystemStatus(settings.ApiKey, settings.FullUri); return new TesterResultModel { IsValid = result.urlBase == settings.SubDir || string.IsNullOrEmpty(result.urlBase) && string.IsNullOrEmpty(settings.SubDir), ExpectedSubDir = result.urlBase }; } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test Radarr"); return new TesterResultModel { IsValid = false }; } } /// /// Checks if we can connect to Sonarr with the provided settings /// /// /// [HttpPost("sonarr")] public async Task Sonarr([FromBody] SonarrSettings settings) { try { if (string.IsNullOrEmpty(settings.ApiKey)) { return new TesterResultModel { IsValid = false, AdditionalInformation = "NullApiKey" }; } if (string.IsNullOrEmpty(settings.Ip)) { return new TesterResultModel { IsValid = false, AdditionalInformation = "NullIp" }; } if (settings.Port <= 0) { return new TesterResultModel { IsValid = false, AdditionalInformation = "BadPort" }; } var result = await SonarrApi.SystemStatus(settings.ApiKey, settings.FullUri); return new TesterResultModel { IsValid = result.urlBase == settings.SubDir || string.IsNullOrEmpty(result.urlBase) && string.IsNullOrEmpty(settings.SubDir), Version = result.version, ExpectedSubDir = result.urlBase }; } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test Sonarr"); return new TesterResultModel { IsValid = false }; } } /// /// Checks if we can connect to CouchPotato with the provided settings /// /// /// [HttpPost("couchpotato")] public async Task CouchPotato([FromBody] CouchPotatoSettings settings) { try { var result = await CouchPotatoApi.Status(settings.FullUri, settings.ApiKey); return result?.success ?? false; } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test CP"); return false; } } /// /// Sends a test message to Telegram using the provided settings /// /// The settings. /// [HttpPost("telegram")] public async Task Telegram([FromBody] TelegramSettings settings) { try { settings.Enabled = true; await TelegramNotification.NotifyAsync(new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); return true; } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test Telegram"); return false; } } /// /// Sends a test message to Slack using the provided settings /// /// The settings. /// [HttpPost("sickrage")] public async Task SickRage([FromBody] SickRageSettings settings) { try { settings.Enabled = true; var result = await SickRageApi.Ping(settings.ApiKey, settings.FullUri); return result?.data?.pid != null; } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test SickRage"); return false; } } [HttpPost("newsletter")] public async Task NewsletterTest([FromBody] NewsletterNotificationViewModel settings) { try { settings.Enabled = true; await Newsletter.Start(settings, true); return true; } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test Newsletter"); return false; } } [HttpPost("mobile")] public async Task MobileNotificationTest([FromBody] MobileNotificationTestViewModel settings) { try { await MobileNotification.NotifyAsync(new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1, UserId = settings.UserId }, settings.Settings); return true; } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test Mobile Notifications"); return false; } } [HttpPost("lidarr")] public async Task LidarrTest([FromBody] LidarrSettings settings) { try { var status = await LidarrApi.Status(settings.ApiKey, settings.FullUri); return new TesterResultModel { IsValid = status?.urlBase == settings.SubDir || string.IsNullOrEmpty(status.urlBase) && string.IsNullOrEmpty(settings.SubDir), ExpectedSubDir = status?.urlBase }; } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test Lidarr"); return new TesterResultModel { IsValid = false }; } } [HttpPost("whatsapp")] public async Task WhatsAppTest([FromBody] WhatsAppSettingsViewModel settings) { try { var user = await UserManager.Users.Include(x => x.UserNotificationPreferences).FirstOrDefaultAsync(x => x.UserName == HttpContext.User.Identity.Name); var status = await WhatsAppApi.SendMessage(new WhatsAppModel { From = settings.From, Message = "This is a test from Ombi!", To = user.UserNotificationPreferences.FirstOrDefault(x => x.Agent == NotificationAgent.WhatsApp).Value }, settings.AccountSid, settings.AuthToken); if (status.HasValue()) { return true; } else { return false; } } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test Lidarr"); return false; } } } }