From 952db09e28b1e08065e1f3f85a902a2718960baf Mon Sep 17 00:00:00 2001 From: tidusjar Date: Sat, 11 Jan 2020 00:41:55 +0000 Subject: [PATCH 1/3] Started on whatsapp --- src/Ombi.Api.Twilio/IWhatsAppApi.cs | 9 ++ src/Ombi.Api.Twilio/Ombi.Api.Twilio.csproj | 11 ++ src/Ombi.Api.Twilio/WhatsAppApi.cs | 30 +++++ src/Ombi.Api.Twilio/WhatsAppModel.cs | 9 ++ .../UI/WhatsAppNotificationsViewModel.cs | 21 +++ src/Ombi.DependencyInjection/IocExtensions.cs | 2 + .../Ombi.DependencyInjection.csproj | 1 + src/Ombi.Helpers/LoggingEvents.cs | 1 + src/Ombi.Helpers/NotificationAgent.cs | 1 + .../Agents/WhatsAppNotification.cs | 125 ++++++++++++++++++ .../Ombi.Notifications.csproj | 1 + .../Models/Notifications/WhatsAppSettings.cs | 10 ++ src/Ombi.sln | 9 +- src/Ombi/Controllers/V1/SettingsController.cs | 34 +++++ src/Ombi/Ombi.csproj | 1 + src/Ombi/Startup.cs | 3 - 16 files changed, 264 insertions(+), 4 deletions(-) create mode 100644 src/Ombi.Api.Twilio/IWhatsAppApi.cs create mode 100644 src/Ombi.Api.Twilio/Ombi.Api.Twilio.csproj create mode 100644 src/Ombi.Api.Twilio/WhatsAppApi.cs create mode 100644 src/Ombi.Api.Twilio/WhatsAppModel.cs create mode 100644 src/Ombi.Core/Models/UI/WhatsAppNotificationsViewModel.cs create mode 100644 src/Ombi.Notifications/Agents/WhatsAppNotification.cs create mode 100644 src/Ombi.Settings/Settings/Models/Notifications/WhatsAppSettings.cs diff --git a/src/Ombi.Api.Twilio/IWhatsAppApi.cs b/src/Ombi.Api.Twilio/IWhatsAppApi.cs new file mode 100644 index 000000000..490aaa8fc --- /dev/null +++ b/src/Ombi.Api.Twilio/IWhatsAppApi.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Ombi.Api.Twilio +{ + public interface IWhatsAppApi + { + Task SendMessage(WhatsAppModel message, string accountSid, string authToken); + } +} \ No newline at end of file diff --git a/src/Ombi.Api.Twilio/Ombi.Api.Twilio.csproj b/src/Ombi.Api.Twilio/Ombi.Api.Twilio.csproj new file mode 100644 index 000000000..d55f9680a --- /dev/null +++ b/src/Ombi.Api.Twilio/Ombi.Api.Twilio.csproj @@ -0,0 +1,11 @@ + + + + netstandard2.0 + + + + + + + diff --git a/src/Ombi.Api.Twilio/WhatsAppApi.cs b/src/Ombi.Api.Twilio/WhatsAppApi.cs new file mode 100644 index 000000000..0e5ce4347 --- /dev/null +++ b/src/Ombi.Api.Twilio/WhatsAppApi.cs @@ -0,0 +1,30 @@ +using System; +using System.Threading.Tasks; +using Twilio; +using Twilio.Rest.Api.V2010.Account; +using Twilio.Types; + +namespace Ombi.Api.Twilio +{ + public class WhatsAppApi : IWhatsAppApi + { + + public async Task SendMessage(WhatsAppModel message, string accountSid, string authToken) + { + // Find your Account Sid and Token at twilio.com/console + // DANGER! This is insecure. See http://twil.io/secure + //const string accountSid = "AC8a1b6ab0d9f351be8210ccc8f7930d27"; + //const string authToken = "f280272092780a770f7cd4fb0beed125"; + + TwilioClient.Init(accountSid, authToken); + + var response =await MessageResource.CreateAsync( + body: message.Message, + from: new PhoneNumber($"whatsapp:{message.From}"), + to: new PhoneNumber($"whatsapp:{message.To}") + ); + + return response.Sid; + } + } +} diff --git a/src/Ombi.Api.Twilio/WhatsAppModel.cs b/src/Ombi.Api.Twilio/WhatsAppModel.cs new file mode 100644 index 000000000..e7f4e5c21 --- /dev/null +++ b/src/Ombi.Api.Twilio/WhatsAppModel.cs @@ -0,0 +1,9 @@ +namespace Ombi.Api.Twilio +{ + public class WhatsAppModel + { + public string Message { get; set; } + public string To { get; set; } + public string From { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Core/Models/UI/WhatsAppNotificationsViewModel.cs b/src/Ombi.Core/Models/UI/WhatsAppNotificationsViewModel.cs new file mode 100644 index 000000000..048ec1dfa --- /dev/null +++ b/src/Ombi.Core/Models/UI/WhatsAppNotificationsViewModel.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Ombi.Settings.Settings.Models.Notifications; +using Ombi.Store.Entities; + +namespace Ombi.Core.Models.UI +{ + /// + /// The view model for the notification settings page + /// + /// + public class WhatsAppNotificationsViewModel : WhatsAppSettings + { + /// + /// Gets or sets the notification templates. + /// + /// + /// The notification templates. + /// + public List NotificationTemplates { get; set; } + } +} diff --git a/src/Ombi.DependencyInjection/IocExtensions.cs b/src/Ombi.DependencyInjection/IocExtensions.cs index dd7dcd3b8..66e0a05e6 100644 --- a/src/Ombi.DependencyInjection/IocExtensions.cs +++ b/src/Ombi.DependencyInjection/IocExtensions.cs @@ -64,6 +64,7 @@ using Ombi.Schedule.Processor; using Ombi.Store.Entities; using Quartz.Spi; using Ombi.Api.MusicBrainz; +using Ombi.Api.Twilio; namespace Ombi.DependencyInjection { @@ -147,6 +148,7 @@ namespace Ombi.DependencyInjection services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); } public static void RegisterStore(this IServiceCollection services) { diff --git a/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj b/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj index 59a37d6aa..636e96a3c 100644 --- a/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj +++ b/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj @@ -37,6 +37,7 @@ + diff --git a/src/Ombi.Helpers/LoggingEvents.cs b/src/Ombi.Helpers/LoggingEvents.cs index 0723800ab..7c4bd73f7 100644 --- a/src/Ombi.Helpers/LoggingEvents.cs +++ b/src/Ombi.Helpers/LoggingEvents.cs @@ -33,6 +33,7 @@ namespace Ombi.Helpers public static EventId PushoverNotification => new EventId(4005); public static EventId TelegramNotifcation => new EventId(4006); public static EventId GotifyNotification => new EventId(4007); + public static EventId WhatsApp => new EventId(4008); public static EventId TvSender => new EventId(5000); public static EventId SonarrSender => new EventId(5001); diff --git a/src/Ombi.Helpers/NotificationAgent.cs b/src/Ombi.Helpers/NotificationAgent.cs index 18f28105a..78fe529c0 100644 --- a/src/Ombi.Helpers/NotificationAgent.cs +++ b/src/Ombi.Helpers/NotificationAgent.cs @@ -11,5 +11,6 @@ Mattermost = 6, Mobile = 7, Gotify = 8, + WhatsApp = 9 } } \ No newline at end of file diff --git a/src/Ombi.Notifications/Agents/WhatsAppNotification.cs b/src/Ombi.Notifications/Agents/WhatsAppNotification.cs new file mode 100644 index 000000000..116120e99 --- /dev/null +++ b/src/Ombi.Notifications/Agents/WhatsAppNotification.cs @@ -0,0 +1,125 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Ombi.Core.Settings; +using Ombi.Helpers; +using Ombi.Notifications.Models; +using Ombi.Settings.Settings.Models; +using Ombi.Settings.Settings.Models.Notifications; +using Ombi.Store.Entities; +using Ombi.Store.Repository; +using Ombi.Store.Repository.Requests; +using Ombi.Api.Twilio; + +namespace Ombi.Notifications.Agents +{ + public class WhatsAppNotification : BaseNotification + { + public WhatsAppNotification(IWhatsAppApi api, ISettingsService sn, ILogger log, + INotificationTemplatesRepository r, IMovieRequestRepository m, + ITvRequestRepository t, ISettingsService s + , IRepository sub, IMusicRequestRepository music, + IRepository userPref) : base(sn, r, m, t,s,log, sub, music, userPref) + { + Api = api; + Logger = log; + } + + public override string NotificationName => "WhatsAppNotification"; + + private IWhatsAppApi Api { get; } + private ILogger Logger { get; } + + protected override bool ValidateConfiguration(WhatsAppSettings settings) + { + if (!settings.Enabled) + { + return false; + } + return !settings.AccountSid.IsNullOrEmpty() && !settings.AuthToken.IsNullOrEmpty() && !settings.From.IsNullOrEmpty(); + } + + protected override async Task NewRequest(NotificationOptions model, WhatsAppSettings settings) + { + await Run(model, settings, NotificationType.NewRequest); + } + + protected override async Task NewIssue(NotificationOptions model, WhatsAppSettings settings) + { + await Run(model, settings, NotificationType.Issue); + } + + protected override async Task IssueComment(NotificationOptions model, WhatsAppSettings settings) + { + await Run(model, settings, NotificationType.IssueComment); + } + + protected override async Task IssueResolved(NotificationOptions model, WhatsAppSettings settings) + { + await Run(model, settings, NotificationType.IssueResolved); + } + + protected override async Task AddedToRequestQueue(NotificationOptions model, WhatsAppSettings settings) + { + await Run(model, settings, NotificationType.ItemAddedToFaultQueue); + } + + protected override async Task RequestDeclined(NotificationOptions model, WhatsAppSettings settings) + { + await Run(model, settings, NotificationType.RequestDeclined); + } + + protected override async Task RequestApproved(NotificationOptions model, WhatsAppSettings settings) + { + await Run(model, settings, NotificationType.RequestApproved); + } + + protected override async Task AvailableRequest(NotificationOptions model, WhatsAppSettings settings) + { + await Run(model, settings, NotificationType.RequestAvailable); + } + + protected override async Task Send(NotificationMessage model, WhatsAppSettings settings) + { + try + { + var whatsApp = new WhatsAppModel + { + Message = model.Message, + From = settings.From, + To = ""// TODO + }; + await Api.SendMessage(whatsApp, settings.AccountSid, settings.AuthToken); + } + catch (Exception e) + { + Logger.LogError(LoggingEvents.WhatsApp, e, "Failed to send WhatsApp Notification"); + } + } + + protected override async Task Test(NotificationOptions model, WhatsAppSettings settings) + { + var message = $"This is a test from Ombi, if you can see this then we have successfully pushed a notification!"; + var notification = new NotificationMessage + { + Message = message, + }; + await Send(notification, settings); + } + + private async Task Run(NotificationOptions model, WhatsAppSettings settings, NotificationType type) + { + var parsed = await LoadTemplate(NotificationAgent.WhatsApp, type, model); + if (parsed.Disabled) + { + Logger.LogInformation($"Template {type} is disabled for {NotificationAgent.WhatsApp}"); + return; + } + var notification = new NotificationMessage + { + Message = parsed.Message, + }; + await Send(notification, settings); + } + } +} diff --git a/src/Ombi.Notifications/Ombi.Notifications.csproj b/src/Ombi.Notifications/Ombi.Notifications.csproj index 3015c150d..c613f5b61 100644 --- a/src/Ombi.Notifications/Ombi.Notifications.csproj +++ b/src/Ombi.Notifications/Ombi.Notifications.csproj @@ -22,6 +22,7 @@ + diff --git a/src/Ombi.Settings/Settings/Models/Notifications/WhatsAppSettings.cs b/src/Ombi.Settings/Settings/Models/Notifications/WhatsAppSettings.cs new file mode 100644 index 000000000..caa862c41 --- /dev/null +++ b/src/Ombi.Settings/Settings/Models/Notifications/WhatsAppSettings.cs @@ -0,0 +1,10 @@ +namespace Ombi.Settings.Settings.Models.Notifications +{ + public class WhatsAppSettings : Settings + { + public bool Enabled { get; set; } + public string AccountSid { get; set; } + public string AuthToken { get; set; } + public string From { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.sln b/src/Ombi.sln index d557516c9..78d3898ac 100644 --- a/src/Ombi.sln +++ b/src/Ombi.sln @@ -108,7 +108,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Hubs", "Ombi.Hubs\Ombi EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.GroupMe", "Ombi.Api.GroupMe\Ombi.Api.GroupMe.csproj", "{9266403C-B04D-4C0F-AC39-82F12C781949}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.MusicBrainz", "Ombi.Api.MusicBrainz\Ombi.Api.MusicBrainz.csproj", "{C5C1769B-4197-4410-A160-0EEF39EDDC98}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.MusicBrainz", "Ombi.Api.MusicBrainz\Ombi.Api.MusicBrainz.csproj", "{C5C1769B-4197-4410-A160-0EEF39EDDC98}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Twilio", "Ombi.Api.Twilio\Ombi.Api.Twilio.csproj", "{34E5DD1A-6A90-448B-9E71-64D1ACD6C1A3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -292,6 +294,10 @@ Global {C5C1769B-4197-4410-A160-0EEF39EDDC98}.Debug|Any CPU.Build.0 = Debug|Any CPU {C5C1769B-4197-4410-A160-0EEF39EDDC98}.Release|Any CPU.ActiveCfg = Release|Any CPU {C5C1769B-4197-4410-A160-0EEF39EDDC98}.Release|Any CPU.Build.0 = Release|Any CPU + {34E5DD1A-6A90-448B-9E71-64D1ACD6C1A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {34E5DD1A-6A90-448B-9E71-64D1ACD6C1A3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {34E5DD1A-6A90-448B-9E71-64D1ACD6C1A3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {34E5DD1A-6A90-448B-9E71-64D1ACD6C1A3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -334,6 +340,7 @@ Global {27111E7C-748E-4996-BD71-2117027C6460} = {6F42AB98-9196-44C4-B888-D5E409F415A1} {9266403C-B04D-4C0F-AC39-82F12C781949} = {9293CA11-360A-4C20-A674-B9E794431BF5} {C5C1769B-4197-4410-A160-0EEF39EDDC98} = {9293CA11-360A-4C20-A674-B9E794431BF5} + {34E5DD1A-6A90-448B-9E71-64D1ACD6C1A3} = {9293CA11-360A-4C20-A674-B9E794431BF5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {192E9BF8-00B4-45E4-BCCC-4C215725C869} diff --git a/src/Ombi/Controllers/V1/SettingsController.cs b/src/Ombi/Controllers/V1/SettingsController.cs index 26ac4053f..d3bf7845c 100644 --- a/src/Ombi/Controllers/V1/SettingsController.cs +++ b/src/Ombi/Controllers/V1/SettingsController.cs @@ -963,6 +963,40 @@ namespace Ombi.Controllers.V1 return model; } + /// + /// Gets the WhatsApp Notification Settings. + /// + /// + [HttpGet("notifications/whatsapp")] + public async Task WhatsAppNotificationSettings() + { + var settings = await Get(); + var model = Mapper.Map(settings); + + // Lookup to see if we have any templates saved + model.NotificationTemplates = BuildTemplates(NotificationAgent.WhatsApp); + + return model; + } + + /// + /// Saves the Mattermost notification settings. + /// + /// The model. + /// + [HttpPost("notifications/whatsapp")] + public async Task WhatsAppNotificationSettings([FromBody] WhatsAppNotificationsViewModel model) + { + // Save the email settings + var settings = Mapper.Map(model); + var result = await Save(settings); + + // Save the templates + await TemplateRepository.UpdateRange(model.NotificationTemplates); + + return result; + } + /// /// Saves the Mobile notification settings. /// diff --git a/src/Ombi/Ombi.csproj b/src/Ombi/Ombi.csproj index 30b63a904..883dad833 100644 --- a/src/Ombi/Ombi.csproj +++ b/src/Ombi/Ombi.csproj @@ -81,6 +81,7 @@ + diff --git a/src/Ombi/Startup.cs b/src/Ombi/Startup.cs index 9bb5ef629..db794a490 100644 --- a/src/Ombi/Startup.cs +++ b/src/Ombi/Startup.cs @@ -2,12 +2,10 @@ using AutoMapper.EquivalencyExpression; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.StaticFiles; -using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -24,7 +22,6 @@ using Ombi.Store.Context; using Ombi.Store.Entities; using Ombi.Store.Repository; using Serilog; -using SQLitePCL; using System; using System.IO; using Microsoft.AspNetCore.StaticFiles.Infrastructure; From 0c7b6a8ed096b21f8c742ca74f7a616977f23803 Mon Sep 17 00:00:00 2001 From: Jamie Rees Date: Sat, 1 Feb 2020 22:32:36 +0000 Subject: [PATCH 2/3] more wip on whatsapp --- ...iewModel.cs => TwilioSettingsViewModel.cs} | 10 ++- src/Ombi.Mapping/Profiles/SettingsProfile.cs | 2 + .../Agents/WhatsAppNotification.cs | 36 +++++----- ...{WhatsAppSettings.cs => TwilioSettings.cs} | 9 ++- .../app/interfaces/INotificationSettings.ts | 28 ++++++-- .../src/app/services/settings.service.ts | 10 +++ .../notificationtemplate.component.html | 52 ++++++--------- .../twilio/twilio.component.html | 21 ++++++ .../notifications/twilio/twilio.component.ts | 55 ++++++++++++++++ .../twilio/whatsapp.component.html | 35 ++++++++++ .../twilio/whatsapp.component.ts | 37 +++++++++++ .../src/app/settings/settings.module.ts | 5 ++ .../app/settings/settingsmenu.component.html | 65 ++++++++++--------- src/Ombi/Controllers/V1/SettingsController.cs | 24 ++++--- 14 files changed, 289 insertions(+), 100 deletions(-) rename src/Ombi.Core/Models/UI/{WhatsAppNotificationsViewModel.cs => TwilioSettingsViewModel.cs} (62%) rename src/Ombi.Settings/Settings/Models/Notifications/{WhatsAppSettings.cs => TwilioSettings.cs} (61%) create mode 100644 src/Ombi/ClientApp/src/app/settings/notifications/twilio/twilio.component.html create mode 100644 src/Ombi/ClientApp/src/app/settings/notifications/twilio/twilio.component.ts create mode 100644 src/Ombi/ClientApp/src/app/settings/notifications/twilio/whatsapp.component.html create mode 100644 src/Ombi/ClientApp/src/app/settings/notifications/twilio/whatsapp.component.ts diff --git a/src/Ombi.Core/Models/UI/WhatsAppNotificationsViewModel.cs b/src/Ombi.Core/Models/UI/TwilioSettingsViewModel.cs similarity index 62% rename from src/Ombi.Core/Models/UI/WhatsAppNotificationsViewModel.cs rename to src/Ombi.Core/Models/UI/TwilioSettingsViewModel.cs index 048ec1dfa..5e19535ad 100644 --- a/src/Ombi.Core/Models/UI/WhatsAppNotificationsViewModel.cs +++ b/src/Ombi.Core/Models/UI/TwilioSettingsViewModel.cs @@ -7,8 +7,14 @@ namespace Ombi.Core.Models.UI /// /// The view model for the notification settings page /// - /// - public class WhatsAppNotificationsViewModel : WhatsAppSettings + /// + public class TwilioSettingsViewModel + { + public int Id { get; set; } + public WhatsAppSettingsViewModel WhatsAppSettings { get; set; } = new WhatsAppSettingsViewModel(); + } + + public class WhatsAppSettingsViewModel : WhatsAppSettings { /// /// Gets or sets the notification templates. diff --git a/src/Ombi.Mapping/Profiles/SettingsProfile.cs b/src/Ombi.Mapping/Profiles/SettingsProfile.cs index f460ce78b..f336db5f9 100644 --- a/src/Ombi.Mapping/Profiles/SettingsProfile.cs +++ b/src/Ombi.Mapping/Profiles/SettingsProfile.cs @@ -20,6 +20,8 @@ namespace Ombi.Mapping.Profiles CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); } } } \ No newline at end of file diff --git a/src/Ombi.Notifications/Agents/WhatsAppNotification.cs b/src/Ombi.Notifications/Agents/WhatsAppNotification.cs index 116120e99..860acc8d0 100644 --- a/src/Ombi.Notifications/Agents/WhatsAppNotification.cs +++ b/src/Ombi.Notifications/Agents/WhatsAppNotification.cs @@ -13,9 +13,9 @@ using Ombi.Api.Twilio; namespace Ombi.Notifications.Agents { - public class WhatsAppNotification : BaseNotification + public class WhatsAppNotification : BaseNotification { - public WhatsAppNotification(IWhatsAppApi api, ISettingsService sn, ILogger log, + public WhatsAppNotification(IWhatsAppApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, ISettingsService s , IRepository sub, IMusicRequestRepository music, @@ -30,66 +30,66 @@ namespace Ombi.Notifications.Agents private IWhatsAppApi Api { get; } private ILogger Logger { get; } - protected override bool ValidateConfiguration(WhatsAppSettings settings) + protected override bool ValidateConfiguration(TwilioSettings settings) { - if (!settings.Enabled) + if (!settings.WhatsAppSettings?.Enabled ?? false) { return false; } - return !settings.AccountSid.IsNullOrEmpty() && !settings.AuthToken.IsNullOrEmpty() && !settings.From.IsNullOrEmpty(); + return !settings.WhatsAppSettings.AccountSid.IsNullOrEmpty() && !settings.WhatsAppSettings.AuthToken.IsNullOrEmpty() && !settings.WhatsAppSettings.From.IsNullOrEmpty(); } - protected override async Task NewRequest(NotificationOptions model, WhatsAppSettings settings) + protected override async Task NewRequest(NotificationOptions model, TwilioSettings settings) { await Run(model, settings, NotificationType.NewRequest); } - protected override async Task NewIssue(NotificationOptions model, WhatsAppSettings settings) + protected override async Task NewIssue(NotificationOptions model, TwilioSettings settings) { await Run(model, settings, NotificationType.Issue); } - protected override async Task IssueComment(NotificationOptions model, WhatsAppSettings settings) + protected override async Task IssueComment(NotificationOptions model, TwilioSettings settings) { await Run(model, settings, NotificationType.IssueComment); } - protected override async Task IssueResolved(NotificationOptions model, WhatsAppSettings settings) + protected override async Task IssueResolved(NotificationOptions model, TwilioSettings settings) { await Run(model, settings, NotificationType.IssueResolved); } - protected override async Task AddedToRequestQueue(NotificationOptions model, WhatsAppSettings settings) + protected override async Task AddedToRequestQueue(NotificationOptions model, TwilioSettings settings) { await Run(model, settings, NotificationType.ItemAddedToFaultQueue); } - protected override async Task RequestDeclined(NotificationOptions model, WhatsAppSettings settings) + protected override async Task RequestDeclined(NotificationOptions model, TwilioSettings settings) { await Run(model, settings, NotificationType.RequestDeclined); } - protected override async Task RequestApproved(NotificationOptions model, WhatsAppSettings settings) + protected override async Task RequestApproved(NotificationOptions model, TwilioSettings settings) { await Run(model, settings, NotificationType.RequestApproved); } - protected override async Task AvailableRequest(NotificationOptions model, WhatsAppSettings settings) + protected override async Task AvailableRequest(NotificationOptions model, TwilioSettings settings) { await Run(model, settings, NotificationType.RequestAvailable); } - protected override async Task Send(NotificationMessage model, WhatsAppSettings settings) + protected override async Task Send(NotificationMessage model, TwilioSettings settings) { try { var whatsApp = new WhatsAppModel { Message = model.Message, - From = settings.From, + From = settings.WhatsAppSettings.From, To = ""// TODO }; - await Api.SendMessage(whatsApp, settings.AccountSid, settings.AuthToken); + await Api.SendMessage(whatsApp, settings.WhatsAppSettings.AccountSid, settings.WhatsAppSettings.AuthToken); } catch (Exception e) { @@ -97,7 +97,7 @@ namespace Ombi.Notifications.Agents } } - protected override async Task Test(NotificationOptions model, WhatsAppSettings settings) + protected override async Task Test(NotificationOptions model, TwilioSettings settings) { var message = $"This is a test from Ombi, if you can see this then we have successfully pushed a notification!"; var notification = new NotificationMessage @@ -107,7 +107,7 @@ namespace Ombi.Notifications.Agents await Send(notification, settings); } - private async Task Run(NotificationOptions model, WhatsAppSettings settings, NotificationType type) + private async Task Run(NotificationOptions model, TwilioSettings settings, NotificationType type) { var parsed = await LoadTemplate(NotificationAgent.WhatsApp, type, model); if (parsed.Disabled) diff --git a/src/Ombi.Settings/Settings/Models/Notifications/WhatsAppSettings.cs b/src/Ombi.Settings/Settings/Models/Notifications/TwilioSettings.cs similarity index 61% rename from src/Ombi.Settings/Settings/Models/Notifications/WhatsAppSettings.cs rename to src/Ombi.Settings/Settings/Models/Notifications/TwilioSettings.cs index caa862c41..d4b0d69ba 100644 --- a/src/Ombi.Settings/Settings/Models/Notifications/WhatsAppSettings.cs +++ b/src/Ombi.Settings/Settings/Models/Notifications/TwilioSettings.cs @@ -1,10 +1,15 @@ namespace Ombi.Settings.Settings.Models.Notifications { - public class WhatsAppSettings : Settings + public class TwilioSettings : Settings + { + public WhatsAppSettings WhatsAppSettings { get; set; } + } + + public class WhatsAppSettings { public bool Enabled { get; set; } + public string From { get; set; } public string AccountSid { get; set; } public string AuthToken { get; set; } - public string From { get; set; } } } \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/interfaces/INotificationSettings.ts b/src/Ombi/ClientApp/src/app/interfaces/INotificationSettings.ts index 5472a6c7c..a6c14ae3b 100644 --- a/src/Ombi/ClientApp/src/app/interfaces/INotificationSettings.ts +++ b/src/Ombi/ClientApp/src/app/interfaces/INotificationSettings.ts @@ -27,11 +27,16 @@ export interface INotificationTemplates { } export enum NotificationAgent { - Email, - Discord, - Pushbullet, - Pushover, - Telegram, + Email = 0, + Discord = 1, + Pushbullet = 2, + Pushover = 3, + Telegram = 4, + Slack = 5, + Mattermost = 6, + Mobile = 7, + Gotify = 8, + WhatsApp = 9 } export enum NotificationType { @@ -47,6 +52,7 @@ export enum NotificationType { IssueResolved = 9, IssueComment = 10, Newsletter = 11, + WhatsApp = 12, } export interface IDiscordNotifcationSettings extends INotificationSettings { @@ -85,6 +91,18 @@ export interface IPushbulletNotificationSettings extends INotificationSettings { channelTag: string; } +export interface ITwilioSettings extends ISettings { + whatsAppSettings: IWhatsAppSettings; +} + +export interface IWhatsAppSettings { + enabled: number; + from: string; + accountSid: string; + authToken: string; + notificationTemplates: INotificationTemplates[]; +} + export interface IPushoverNotificationSettings extends INotificationSettings { accessToken: string; notificationTemplates: INotificationTemplates[]; diff --git a/src/Ombi/ClientApp/src/app/services/settings.service.ts b/src/Ombi/ClientApp/src/app/services/settings.service.ts index fb50f3e89..4eec29081 100644 --- a/src/Ombi/ClientApp/src/app/services/settings.service.ts +++ b/src/Ombi/ClientApp/src/app/services/settings.service.ts @@ -36,6 +36,7 @@ import { IUpdateSettings, IUserManagementSettings, IVoteSettings, + ITwilioSettings, } from "../interfaces"; import { ServiceHelpers } from "./service.helpers"; @@ -254,6 +255,15 @@ export class SettingsService extends ServiceHelpers { .post(`${this.url}/notifications/telegram`, JSON.stringify(settings), {headers: this.headers}); } + public getTwilioSettings(): Observable { + return this.http.get(`${this.url}/notifications/twilio`, {headers: this.headers}); + } + + public saveTwilioSettings(settings: ITwilioSettings): Observable { + return this.http + .post(`${this.url}/notifications/twilio`, JSON.stringify(settings), {headers: this.headers}); + } + public getJobSettings(): Observable { return this.http.get(`${this.url}/jobs`, {headers: this.headers}); } diff --git a/src/Ombi/ClientApp/src/app/settings/notifications/notificationtemplate.component.html b/src/Ombi/ClientApp/src/app/settings/notifications/notificationtemplate.component.html index 1fd475a38..02551a345 100644 --- a/src/Ombi/ClientApp/src/app/settings/notifications/notificationtemplate.component.html +++ b/src/Ombi/ClientApp/src/app/settings/notifications/notificationtemplate.component.html @@ -1,36 +1,26 @@ - - + +

+ + + + + {{NotificationType[template.notificationType] | humanize}} + + - - - -
-
- -
-
- -
-
- -
- -
- -
-
+
+ Enable +
-
- -
- -
-
-
-
+ + + -
-
-
+ + + +
+ +
\ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/settings/notifications/twilio/twilio.component.html b/src/Ombi/ClientApp/src/app/settings/notifications/twilio/twilio.component.html new file mode 100644 index 000000000..e28ec4115 --- /dev/null +++ b/src/Ombi/ClientApp/src/app/settings/notifications/twilio/twilio.component.html @@ -0,0 +1,21 @@ + + +
+
+ Twilio +
+ + + + + + + +
+
+ +
+
+
+
+
\ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/settings/notifications/twilio/twilio.component.ts b/src/Ombi/ClientApp/src/app/settings/notifications/twilio/twilio.component.ts new file mode 100644 index 000000000..4f2364107 --- /dev/null +++ b/src/Ombi/ClientApp/src/app/settings/notifications/twilio/twilio.component.ts @@ -0,0 +1,55 @@ +import { Component, OnInit } from "@angular/core"; +import { FormBuilder, FormGroup, Validators } from "@angular/forms"; + +import { INotificationTemplates, ITwilioSettings, NotificationType } from "../../../interfaces"; +import { TesterService } from "../../../services"; +import { NotificationService } from "../../../services"; +import { SettingsService } from "../../../services"; + +@Component({ + templateUrl: "./twilio.component.html", +}) +export class TwilioComponent implements OnInit { + public NotificationType = NotificationType; + public templates: INotificationTemplates[]; + public form: FormGroup; + + constructor(private settingsService: SettingsService, + private notificationService: NotificationService, + private fb: FormBuilder, + private testerService: TesterService) { } + + public ngOnInit() { + this.settingsService.getTwilioSettings().subscribe(x => { + this.templates = x.whatsAppSettings.notificationTemplates; + + this.form = this.fb.group({ + whatsAppSettings: this.fb.group({ + enabled: [x.whatsAppSettings.enabled], + accountSid: [x.whatsAppSettings.accountSid], + authToken: [x.whatsAppSettings.authToken], + from: [x.whatsAppSettings.from], + }), + }); + }); + } + + public onSubmit(form: FormGroup) { + if (form.invalid) { + this.notificationService.error("Please check your entered values"); + return; + } + + const settings = form.value; + settings.whatsAppSettings.notificationTemplates = this.templates; + + this.settingsService.saveTwilioSettings(settings).subscribe(x => { + if (x) { + this.notificationService.success("Successfully saved the Twilio settings"); + } else { + this.notificationService.success("There was an error when saving the Twilio settings"); + } + }); + + } +} diff --git a/src/Ombi/ClientApp/src/app/settings/notifications/twilio/whatsapp.component.html b/src/Ombi/ClientApp/src/app/settings/notifications/twilio/whatsapp.component.html new file mode 100644 index 000000000..666cc4cfd --- /dev/null +++ b/src/Ombi/ClientApp/src/app/settings/notifications/twilio/whatsapp.component.html @@ -0,0 +1,35 @@ +
+
+
+
+ Enable +
+ + +
+ + + +
+
+ + + +
+
+ + + +
+
+ +
+ +
+
+
+ +
+
+
+
\ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/settings/notifications/twilio/whatsapp.component.ts b/src/Ombi/ClientApp/src/app/settings/notifications/twilio/whatsapp.component.ts new file mode 100644 index 000000000..e77653d38 --- /dev/null +++ b/src/Ombi/ClientApp/src/app/settings/notifications/twilio/whatsapp.component.ts @@ -0,0 +1,37 @@ +import { Component, Input } from "@angular/core"; +import { FormGroup } from "@angular/forms"; +import { TesterService, NotificationService } from "../../../services"; +import { INotificationTemplates, NotificationType } from "../../../interfaces"; + + + +@Component({ + templateUrl: "./whatsapp.component.html", + selector: "app-whatsapp" +}) +export class WhatsAppComponent { + + public NotificationType = NotificationType; + @Input() public templates: INotificationTemplates[]; + @Input() public form: FormGroup; + + constructor(private testerService: TesterService, + private notificationService: NotificationService) { } + + + public test(form: FormGroup) { + if (form.invalid) { + this.notificationService.error("Please check your entered values"); + return; + } + + this.testerService.mattermostTest(form.value).subscribe(x => { + if (x) { + this.notificationService.success( "Successfully sent a Mattermost message, please check the appropriate channel"); + } else { + this.notificationService.error("There was an error when sending the Mattermost message. Please check your settings"); + } + }); + + } +} diff --git a/src/Ombi/ClientApp/src/app/settings/settings.module.ts b/src/Ombi/ClientApp/src/app/settings/settings.module.ts index e4be0c24e..bdf0596ac 100644 --- a/src/Ombi/ClientApp/src/app/settings/settings.module.ts +++ b/src/Ombi/ClientApp/src/app/settings/settings.module.ts @@ -55,6 +55,8 @@ import { MatMenuModule} from "@angular/material"; import { SharedModule } from "../shared/shared.module"; import { HubService } from "../services/hub.service"; import { LogsComponent } from "./logs/logs.component"; +import { TwilioComponent } from "./notifications/twilio/twilio.component"; +import { WhatsAppComponent } from "./notifications/twilio/whatsapp.component"; const routes: Routes = [ { path: "Ombi", component: OmbiComponent, canActivate: [AuthGuard] }, @@ -72,6 +74,7 @@ const routes: Routes = [ { path: "Pushbullet", component: PushbulletComponent, canActivate: [AuthGuard] }, { path: "Gotify", component: GotifyComponent, canActivate: [AuthGuard] }, { path: "Mattermost", component: MattermostComponent, canActivate: [AuthGuard] }, + { path: "Twilio", component: TwilioComponent, canActivate: [AuthGuard] }, { path: "UserManagement", component: UserManagementComponent, canActivate: [AuthGuard] }, { path: "Update", component: UpdateComponent, canActivate: [AuthGuard] }, { path: "CouchPotato", component: CouchPotatoComponent, canActivate: [AuthGuard] }, @@ -149,6 +152,8 @@ const routes: Routes = [ TheMovieDbComponent, FailedRequestsComponent, LogsComponent, + TwilioComponent, + WhatsAppComponent ], exports: [ RouterModule, diff --git a/src/Ombi/ClientApp/src/app/settings/settingsmenu.component.html b/src/Ombi/ClientApp/src/app/settings/settingsmenu.component.html index 41a5c5d66..21f01d010 100644 --- a/src/Ombi/ClientApp/src/app/settings/settingsmenu.component.html +++ b/src/Ombi/ClientApp/src/app/settings/settingsmenu.component.html @@ -2,62 +2,63 @@ - - - - - - - + + + + + + + - - + + - - - + + + - - - + + + - + - - - - - - - - - - - + + + + + + + + + + + + - - - - - + + + + +
\ No newline at end of file diff --git a/src/Ombi/Controllers/V1/SettingsController.cs b/src/Ombi/Controllers/V1/SettingsController.cs index d3bf7845c..0575d0914 100644 --- a/src/Ombi/Controllers/V1/SettingsController.cs +++ b/src/Ombi/Controllers/V1/SettingsController.cs @@ -964,17 +964,21 @@ namespace Ombi.Controllers.V1 } /// - /// Gets the WhatsApp Notification Settings. + /// Gets the Twilio Notification Settings. /// /// - [HttpGet("notifications/whatsapp")] - public async Task WhatsAppNotificationSettings() + [HttpGet("notifications/twilio")] + public async Task TwilioNotificationSettings() { - var settings = await Get(); - var model = Mapper.Map(settings); + var settings = await Get(); + var model = Mapper.Map(settings); // Lookup to see if we have any templates saved - model.NotificationTemplates = BuildTemplates(NotificationAgent.WhatsApp); + if(model.WhatsAppSettings == null) + { + model.WhatsAppSettings = new WhatsAppSettingsViewModel(); + } + model.WhatsAppSettings.NotificationTemplates = BuildTemplates(NotificationAgent.WhatsApp); return model; } @@ -984,15 +988,15 @@ namespace Ombi.Controllers.V1 ///
/// The model. /// - [HttpPost("notifications/whatsapp")] - public async Task WhatsAppNotificationSettings([FromBody] WhatsAppNotificationsViewModel model) + [HttpPost("notifications/twilio")] + public async Task TwilioNotificationSettings([FromBody] TwilioSettingsViewModel model) { // Save the email settings - var settings = Mapper.Map(model); + var settings = Mapper.Map(model); var result = await Save(settings); // Save the templates - await TemplateRepository.UpdateRange(model.NotificationTemplates); + await TemplateRepository.UpdateRange(model.WhatsAppSettings.NotificationTemplates); return result; } From 8a94298a8027194b7bd87ed9b1feaca1da5f718e Mon Sep 17 00:00:00 2001 From: Jamie Rees Date: Sat, 1 Feb 2020 23:15:53 +0000 Subject: [PATCH 3/3] Finished whatsapp --- src/Ombi.Api.Twilio/WhatsAppApi.cs | 6 --- .../ClientApp/src/app/interfaces/IUser.ts | 3 ++ .../services/applications/tester.service.ts | 5 +++ .../twilio/whatsapp.component.html | 2 +- .../twilio/whatsapp.component.ts | 6 +-- .../V1/External/TesterController.cs | 41 ++++++++++++++++++- 6 files changed, 51 insertions(+), 12 deletions(-) diff --git a/src/Ombi.Api.Twilio/WhatsAppApi.cs b/src/Ombi.Api.Twilio/WhatsAppApi.cs index 0e5ce4347..5290a02ec 100644 --- a/src/Ombi.Api.Twilio/WhatsAppApi.cs +++ b/src/Ombi.Api.Twilio/WhatsAppApi.cs @@ -8,14 +8,8 @@ namespace Ombi.Api.Twilio { public class WhatsAppApi : IWhatsAppApi { - public async Task SendMessage(WhatsAppModel message, string accountSid, string authToken) { - // Find your Account Sid and Token at twilio.com/console - // DANGER! This is insecure. See http://twil.io/secure - //const string accountSid = "AC8a1b6ab0d9f351be8210ccc8f7930d27"; - //const string authToken = "f280272092780a770f7cd4fb0beed125"; - TwilioClient.Init(accountSid, authToken); var response =await MessageResource.CreateAsync( diff --git a/src/Ombi/ClientApp/src/app/interfaces/IUser.ts b/src/Ombi/ClientApp/src/app/interfaces/IUser.ts index 0816ad42e..9b0500891 100644 --- a/src/Ombi/ClientApp/src/app/interfaces/IUser.ts +++ b/src/Ombi/ClientApp/src/app/interfaces/IUser.ts @@ -91,6 +91,7 @@ export interface INotificationPreferences { } export enum INotificationAgent { + Email = 0, Discord = 1, Pushbullet = 2, @@ -99,4 +100,6 @@ export enum INotificationAgent { Slack = 5, Mattermost = 6, Mobile = 7, + Gotify = 8, + WhatsApp = 9 } diff --git a/src/Ombi/ClientApp/src/app/services/applications/tester.service.ts b/src/Ombi/ClientApp/src/app/services/applications/tester.service.ts index 1b7c55821..6c1d9ff6c 100644 --- a/src/Ombi/ClientApp/src/app/services/applications/tester.service.ts +++ b/src/Ombi/ClientApp/src/app/services/applications/tester.service.ts @@ -24,6 +24,7 @@ import { ISlackNotificationSettings, ISonarrSettings, ITelegramNotifcationSettings, + IWhatsAppSettings, } from "../../interfaces"; @Injectable() @@ -52,6 +53,10 @@ export class TesterService extends ServiceHelpers { return this.http.post(`${this.url}mattermost`, JSON.stringify(settings), {headers: this.headers}); } + public whatsAppTest(settings: IWhatsAppSettings): Observable { + return this.http.post(`${this.url}whatsapp`, JSON.stringify(settings), {headers: this.headers}); + } + public slackTest(settings: ISlackNotificationSettings): Observable { return this.http.post(`${this.url}slack`, JSON.stringify(settings), {headers: this.headers}); } diff --git a/src/Ombi/ClientApp/src/app/settings/notifications/twilio/whatsapp.component.html b/src/Ombi/ClientApp/src/app/settings/notifications/twilio/whatsapp.component.html index 666cc4cfd..1b6b155b8 100644 --- a/src/Ombi/ClientApp/src/app/settings/notifications/twilio/whatsapp.component.html +++ b/src/Ombi/ClientApp/src/app/settings/notifications/twilio/whatsapp.component.html @@ -28,7 +28,7 @@
- +
diff --git a/src/Ombi/ClientApp/src/app/settings/notifications/twilio/whatsapp.component.ts b/src/Ombi/ClientApp/src/app/settings/notifications/twilio/whatsapp.component.ts index e77653d38..80222e426 100644 --- a/src/Ombi/ClientApp/src/app/settings/notifications/twilio/whatsapp.component.ts +++ b/src/Ombi/ClientApp/src/app/settings/notifications/twilio/whatsapp.component.ts @@ -25,11 +25,11 @@ export class WhatsAppComponent { return; } - this.testerService.mattermostTest(form.value).subscribe(x => { + this.testerService.whatsAppTest(form.get("whatsAppSettings").value).subscribe(x => { if (x) { - this.notificationService.success( "Successfully sent a Mattermost message, please check the appropriate channel"); + this.notificationService.success( "Successfully sent a WhatsApp message, please check the appropriate channel"); } else { - this.notificationService.error("There was an error when sending the Mattermost message. Please check your settings"); + this.notificationService.error("There was an error when sending the WhatsApp message. Please check your settings"); } }); diff --git a/src/Ombi/Controllers/V1/External/TesterController.cs b/src/Ombi/Controllers/V1/External/TesterController.cs index 5a52adfb1..969e619ea 100644 --- a/src/Ombi/Controllers/V1/External/TesterController.cs +++ b/src/Ombi/Controllers/V1/External/TesterController.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Ombi.Api.CouchPotato; using Ombi.Api.Emby; @@ -10,7 +11,9 @@ 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.UI; using Ombi.Core.Notifications; using Ombi.Core.Settings.Models.External; @@ -22,6 +25,7 @@ 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 { @@ -40,7 +44,7 @@ namespace Ombi.Controllers.V1.External IPushbulletNotification pushbullet, ISlackNotification slack, IPushoverNotification po, IMattermostNotification mm, IPlexApi plex, IEmbyApi emby, IRadarrApi radarr, ISonarrApi sonarr, ILogger log, IEmailProvider provider, ICouchPotatoApi cpApi, ITelegramNotification telegram, ISickRageApi srApi, INewsletterJob newsletter, IMobileNotification mobileNotification, - ILidarrApi lidarrApi, IGotifyNotification gotifyNotification) + ILidarrApi lidarrApi, IGotifyNotification gotifyNotification, IWhatsAppApi whatsAppApi, OmbiUserManager um) { Service = service; DiscordNotification = notification; @@ -62,6 +66,8 @@ namespace Ombi.Controllers.V1.External MobileNotification = mobileNotification; LidarrApi = lidarrApi; GotifyNotification = gotifyNotification; + WhatsAppApi = whatsAppApi; + UserManager = um; } private INotificationService Service { get; } @@ -84,7 +90,8 @@ namespace Ombi.Controllers.V1.External private INewsletterJob Newsletter { get; } private IMobileNotification MobileNotification { get; } private ILidarrApi LidarrApi { get; } - + private IWhatsAppApi WhatsAppApi { get; } + private OmbiUserManager UserManager {get;} /// /// Sends a test message to discord using the provided settings @@ -459,5 +466,35 @@ namespace Ombi.Controllers.V1.External return 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; + } + } } } \ No newline at end of file