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..5290a02ec --- /dev/null +++ b/src/Ombi.Api.Twilio/WhatsAppApi.cs @@ -0,0 +1,24 @@ +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) + { + 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/TwilioSettingsViewModel.cs b/src/Ombi.Core/Models/UI/TwilioSettingsViewModel.cs new file mode 100644 index 000000000..5e19535ad --- /dev/null +++ b/src/Ombi.Core/Models/UI/TwilioSettingsViewModel.cs @@ -0,0 +1,27 @@ +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 TwilioSettingsViewModel + { + public int Id { get; set; } + public WhatsAppSettingsViewModel WhatsAppSettings { get; set; } = new WhatsAppSettingsViewModel(); + } + + public class WhatsAppSettingsViewModel : 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.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 new file mode 100644 index 000000000..860acc8d0 --- /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(TwilioSettings settings) + { + if (!settings.WhatsAppSettings?.Enabled ?? false) + { + return false; + } + return !settings.WhatsAppSettings.AccountSid.IsNullOrEmpty() && !settings.WhatsAppSettings.AuthToken.IsNullOrEmpty() && !settings.WhatsAppSettings.From.IsNullOrEmpty(); + } + + protected override async Task NewRequest(NotificationOptions model, TwilioSettings settings) + { + await Run(model, settings, NotificationType.NewRequest); + } + + protected override async Task NewIssue(NotificationOptions model, TwilioSettings settings) + { + await Run(model, settings, NotificationType.Issue); + } + + protected override async Task IssueComment(NotificationOptions model, TwilioSettings settings) + { + await Run(model, settings, NotificationType.IssueComment); + } + + protected override async Task IssueResolved(NotificationOptions model, TwilioSettings settings) + { + await Run(model, settings, NotificationType.IssueResolved); + } + + protected override async Task AddedToRequestQueue(NotificationOptions model, TwilioSettings settings) + { + await Run(model, settings, NotificationType.ItemAddedToFaultQueue); + } + + protected override async Task RequestDeclined(NotificationOptions model, TwilioSettings settings) + { + await Run(model, settings, NotificationType.RequestDeclined); + } + + protected override async Task RequestApproved(NotificationOptions model, TwilioSettings settings) + { + await Run(model, settings, NotificationType.RequestApproved); + } + + protected override async Task AvailableRequest(NotificationOptions model, TwilioSettings settings) + { + await Run(model, settings, NotificationType.RequestAvailable); + } + + protected override async Task Send(NotificationMessage model, TwilioSettings settings) + { + try + { + var whatsApp = new WhatsAppModel + { + Message = model.Message, + From = settings.WhatsAppSettings.From, + To = ""// TODO + }; + await Api.SendMessage(whatsApp, settings.WhatsAppSettings.AccountSid, settings.WhatsAppSettings.AuthToken); + } + catch (Exception e) + { + Logger.LogError(LoggingEvents.WhatsApp, e, "Failed to send WhatsApp Notification"); + } + } + + 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 + { + Message = message, + }; + await Send(notification, settings); + } + + private async Task Run(NotificationOptions model, TwilioSettings 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/TwilioSettings.cs b/src/Ombi.Settings/Settings/Models/Notifications/TwilioSettings.cs new file mode 100644 index 000000000..d4b0d69ba --- /dev/null +++ b/src/Ombi.Settings/Settings/Models/Notifications/TwilioSettings.cs @@ -0,0 +1,15 @@ +namespace Ombi.Settings.Settings.Models.Notifications +{ + 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; } + } +} \ 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/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/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/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..1b6b155b8 --- /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..80222e426 --- /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.whatsAppTest(form.get("whatsAppSettings").value).subscribe(x => { + if (x) { + this.notificationService.success( "Successfully sent a WhatsApp message, please check the appropriate channel"); + } else { + this.notificationService.error("There was an error when sending the WhatsApp 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/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 diff --git a/src/Ombi/Controllers/V1/SettingsController.cs b/src/Ombi/Controllers/V1/SettingsController.cs index 2543ff842..ea65e63cb 100644 --- a/src/Ombi/Controllers/V1/SettingsController.cs +++ b/src/Ombi/Controllers/V1/SettingsController.cs @@ -963,6 +963,44 @@ namespace Ombi.Controllers.V1 return model; } + /// + /// Gets the Twilio Notification Settings. + /// + /// + [HttpGet("notifications/twilio")] + public async Task TwilioNotificationSettings() + { + var settings = await Get(); + var model = Mapper.Map(settings); + + // Lookup to see if we have any templates saved + if(model.WhatsAppSettings == null) + { + model.WhatsAppSettings = new WhatsAppSettingsViewModel(); + } + model.WhatsAppSettings.NotificationTemplates = BuildTemplates(NotificationAgent.WhatsApp); + + return model; + } + + /// + /// Saves the Mattermost notification settings. + /// + /// The model. + /// + [HttpPost("notifications/twilio")] + public async Task TwilioNotificationSettings([FromBody] TwilioSettingsViewModel model) + { + // Save the email settings + var settings = Mapper.Map(model); + var result = await Save(settings); + + // Save the templates + await TemplateRepository.UpdateRange(model.WhatsAppSettings.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 9a5667316..44d37509d 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;