diff --git a/src/Ombi.Api.Slack/ISlackApi.cs b/src/Ombi.Api.Slack/ISlackApi.cs new file mode 100644 index 000000000..1dafd7a49 --- /dev/null +++ b/src/Ombi.Api.Slack/ISlackApi.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; +using Ombi.Api.Slack.Models; + +namespace Ombi.Api.Slack +{ + public interface ISlackApi + { + Task PushAsync(string team, string token, string service, SlackNotificationBody message); + } +} \ No newline at end of file diff --git a/src/Ombi.Api.Slack/Models/SlackNotificationBody.cs b/src/Ombi.Api.Slack/Models/SlackNotificationBody.cs new file mode 100644 index 000000000..0621cf1be --- /dev/null +++ b/src/Ombi.Api.Slack/Models/SlackNotificationBody.cs @@ -0,0 +1,30 @@ +using Newtonsoft.Json; + +namespace Ombi.Api.Slack.Models +{ + public class SlackNotificationBody + { + [JsonConstructor] + public SlackNotificationBody() + { + username = "Ombi"; + } + + [JsonIgnore] + private string _username; + public string username + { + get => _username; + set + { + if (!string.IsNullOrEmpty(value)) + _username = value; + } + } + public string channel { get; set; } + public string text { get; set; } + + public string icon_url { get; set; } + public string icon_emoji { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Api.Slack/Ombi.Api.Slack.csproj b/src/Ombi.Api.Slack/Ombi.Api.Slack.csproj new file mode 100644 index 000000000..a8c3e7a4c --- /dev/null +++ b/src/Ombi.Api.Slack/Ombi.Api.Slack.csproj @@ -0,0 +1,11 @@ + + + + netstandard1.6 + + + + + + + \ No newline at end of file diff --git a/src/Ombi.Api.Slack/SlackApi.cs b/src/Ombi.Api.Slack/SlackApi.cs new file mode 100644 index 000000000..c3c7cdc5c --- /dev/null +++ b/src/Ombi.Api.Slack/SlackApi.cs @@ -0,0 +1,42 @@ +using System; +using System.Dynamic; +using System.Net.Http; +using System.Threading.Tasks; +using Ombi.Api.Slack.Models; + +namespace Ombi.Api.Slack +{ + public class SlackApi : ISlackApi + { + public SlackApi(IApi api) + { + Api = api; + } + + private IApi Api { get; } + private const string BaseUrl = "https://hooks.slack.com/"; + public async Task PushAsync(string team, string token, string service, SlackNotificationBody message) + { + + var request = new Request($"/services/{team}/{service}/{token}", BaseUrl, HttpMethod.Post); + dynamic body = new ExpandoObject(); + body.channel = message.channel; + body.text = message.text; + body.username = message.username; + + if (!string.IsNullOrEmpty(message.icon_url)) + { + body.icon_url = message.icon_url; + } + + if (!string.IsNullOrEmpty(message.icon_emoji)) + { + body.icon_emoji = message.icon_emoji; + } + request.AddJsonBody(body); + request.ApplicationJsonContentType(); + + return await Api.Request(request); + } + } +} diff --git a/src/Ombi.Core/Models/UI/SlackNotificationsViewModel.cs b/src/Ombi.Core/Models/UI/SlackNotificationsViewModel.cs new file mode 100644 index 000000000..951006d6d --- /dev/null +++ b/src/Ombi.Core/Models/UI/SlackNotificationsViewModel.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 SlackNotificationsViewModel : SlackNotificationSettings + { + /// + /// 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 317535040..45c2fb0fd 100644 --- a/src/Ombi.DependencyInjection/IocExtensions.cs +++ b/src/Ombi.DependencyInjection/IocExtensions.cs @@ -30,6 +30,7 @@ using Ombi.Api; using Ombi.Api.FanartTv; using Ombi.Api.Pushbullet; using Ombi.Api.Service; +using Ombi.Api.Slack; using Ombi.Core.Rule.Interfaces; using Ombi.Core.Senders; using Ombi.Schedule.Ombi; @@ -68,6 +69,7 @@ namespace Ombi.DependencyInjection services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); @@ -104,6 +106,7 @@ namespace Ombi.DependencyInjection services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); } public static void RegisterJobs(this IServiceCollection services) diff --git a/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj b/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj index 2e5eab0af..414a854e9 100644 --- a/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj +++ b/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj @@ -18,6 +18,7 @@ + diff --git a/src/Ombi.Helpers/LoggingEvents.cs b/src/Ombi.Helpers/LoggingEvents.cs index d60aff837..0381b098d 100644 --- a/src/Ombi.Helpers/LoggingEvents.cs +++ b/src/Ombi.Helpers/LoggingEvents.cs @@ -17,6 +17,7 @@ namespace Ombi.Helpers public static EventId Notification => new EventId(4000); public static EventId DiscordNotification => new EventId(4001); public static EventId PushbulletNotification => new EventId(4002); + public static EventId SlackNotification => new EventId(4003); public static EventId TvSender => new EventId(5000); public static EventId SonarrSender => new EventId(5001); diff --git a/src/Ombi.Mapping/Profiles/SettingsProfile.cs b/src/Ombi.Mapping/Profiles/SettingsProfile.cs index 3268f39e1..cdb38a35b 100644 --- a/src/Ombi.Mapping/Profiles/SettingsProfile.cs +++ b/src/Ombi.Mapping/Profiles/SettingsProfile.cs @@ -11,6 +11,7 @@ namespace Ombi.Mapping.Profiles CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); + CreateMap().ReverseMap(); } } } \ No newline at end of file diff --git a/src/Ombi.Notifications/Agents/ISlackNotification.cs b/src/Ombi.Notifications/Agents/ISlackNotification.cs new file mode 100644 index 000000000..22ec063ad --- /dev/null +++ b/src/Ombi.Notifications/Agents/ISlackNotification.cs @@ -0,0 +1,6 @@ +namespace Ombi.Notifications.Agents +{ + public interface ISlackNotification : INotification + { + } +} \ No newline at end of file diff --git a/src/Ombi.Notifications/Agents/SlackNotification.cs b/src/Ombi.Notifications/Agents/SlackNotification.cs new file mode 100644 index 000000000..d02a19ba0 --- /dev/null +++ b/src/Ombi.Notifications/Agents/SlackNotification.cs @@ -0,0 +1,168 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Ombi.Api.Slack; +using Ombi.Api.Slack.Models; +using Ombi.Core.Settings; +using Ombi.Helpers; +using Ombi.Notifications.Interfaces; +using Ombi.Notifications.Models; +using Ombi.Settings.Settings.Models.Notifications; +using Ombi.Store.Entities; +using Ombi.Store.Repository; +using Ombi.Store.Repository.Requests; + +namespace Ombi.Notifications.Agents +{ + public class SlackNotification : BaseNotification, ISlackNotification + { + public SlackNotification(ISlackApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t) : base(sn, r, m, t) + { + Api = api; + Logger = log; + } + + public override string NotificationName => "SlackNotification"; + + private ISlackApi Api { get; } + private ILogger Logger { get; } + + protected override bool ValidateConfiguration(SlackNotificationSettings settings) + { + if (!settings.Enabled) + { + return false; + } + if (string.IsNullOrEmpty(settings.WebhookUrl)) + { + return false; + } + try + { + var a = settings.Token; + var b = settings.Channel; + var c = settings.Service; + } + catch (IndexOutOfRangeException) + { + return false; + } + return true; + } + + protected override async Task NewRequest(NotificationOptions model, SlackNotificationSettings settings) + { + var parsed = await LoadTemplate(NotificationAgent.Slack, NotificationType.NewRequest, model); + + var notification = new NotificationMessage + { + Message = parsed.Message, + }; + + notification.Other.Add("image", parsed.Image); + await Send(notification, settings); + } + + protected override async Task Issue(NotificationOptions model, SlackNotificationSettings settings) + { + var parsed = await LoadTemplate(NotificationAgent.Slack, NotificationType.Issue, model); + + var notification = new NotificationMessage + { + Message = parsed.Message, + }; + notification.Other.Add("image", parsed.Image); + await Send(notification, settings); + } + + protected override async Task AddedToRequestQueue(NotificationOptions model, SlackNotificationSettings settings) + { + var user = string.Empty; + var title = string.Empty; + if (model.RequestType == RequestType.Movie) + { + user = MovieRequest.RequestedUser.UserAlias; + title = MovieRequest.Title; + } + else + { + user = TvRequest.RequestedUser.UserAlias; + title = TvRequest.ParentRequest.Title; + } + var message = $"Hello! The user '{user}' has requested {title} but it could not be added. This has been added into the requests queue and will keep retrying"; + var notification = new NotificationMessage + { + Message = message + }; + await Send(notification, settings); + } + + protected override async Task RequestDeclined(NotificationOptions model, SlackNotificationSettings settings) + { + var parsed = await LoadTemplate(NotificationAgent.Slack, NotificationType.RequestDeclined, model); + + var notification = new NotificationMessage + { + Message = parsed.Message, + }; + notification.Other.Add("image", parsed.Image); + await Send(notification, settings); + } + + protected override async Task RequestApproved(NotificationOptions model, SlackNotificationSettings settings) + { + var parsed = await LoadTemplate(NotificationAgent.Slack, NotificationType.RequestApproved, model); + + var notification = new NotificationMessage + { + Message = parsed.Message, + }; + + notification.Other.Add("image", parsed.Image); + await Send(notification, settings); + } + + protected override async Task AvailableRequest(NotificationOptions model, SlackNotificationSettings settings) + { + var parsed = await LoadTemplate(NotificationAgent.Slack, NotificationType.RequestAvailable, model); + + var notification = new NotificationMessage + { + Message = parsed.Message, + }; + notification.Other.Add("image", parsed.Image); + await Send(notification, settings); + } + + protected override async Task Send(NotificationMessage model, SlackNotificationSettings settings) + { + try + { + var body = new SlackNotificationBody + { + channel = settings.Channel, + icon_emoji = settings.IconEmoji, + icon_url = settings.IconUrl, + text = model.Message, + username = settings.Username + }; + + await Api.PushAsync(settings.Team, settings.Token, settings.Service, body); + } + catch (Exception e) + { + Logger.LogError(LoggingEvents.SlackNotification, e, "Failed to send Slack Notification"); + } + } + + protected override async Task Test(NotificationOptions model, SlackNotificationSettings 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); + } + } +} diff --git a/src/Ombi.Notifications/Ombi.Notifications.csproj b/src/Ombi.Notifications/Ombi.Notifications.csproj index a3bc8acfa..293861219 100644 --- a/src/Ombi.Notifications/Ombi.Notifications.csproj +++ b/src/Ombi.Notifications/Ombi.Notifications.csproj @@ -11,6 +11,7 @@ + diff --git a/src/Ombi.Settings/Settings/Models/Notifications/SlackNotificationSettings.cs b/src/Ombi.Settings/Settings/Models/Notifications/SlackNotificationSettings.cs new file mode 100644 index 000000000..496e23807 --- /dev/null +++ b/src/Ombi.Settings/Settings/Models/Notifications/SlackNotificationSettings.cs @@ -0,0 +1,38 @@ +using System; +using Newtonsoft.Json; + +namespace Ombi.Settings.Settings.Models.Notifications +{ + public class SlackNotificationSettings : Settings + { + public bool Enabled { get; set; } + public string WebhookUrl { get; set; } + public string Channel { get; set; } + public string Username { get; set; } + public string IconEmoji { get; set; } + public string IconUrl { get; set; } + + [JsonIgnore] + public string Team => SplitWebUrl(3); + + [JsonIgnore] + public string Service => SplitWebUrl(4); + + [JsonIgnore] + public string Token => SplitWebUrl(5); + + private string SplitWebUrl(int index) + { + if (!WebhookUrl.StartsWith("http", StringComparison.CurrentCultureIgnoreCase)) + { + WebhookUrl = "https://" + WebhookUrl; + } + var split = WebhookUrl.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); + + return split.Length < index + ? string.Empty + : split[index]; + } + + } +} \ No newline at end of file diff --git a/src/Ombi.sln b/src/Ombi.sln index 15098fe95..151454a4f 100644 --- a/src/Ombi.sln +++ b/src/Ombi.sln @@ -73,6 +73,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.FanartTv", "Ombi.A EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Pushbullet", "Ombi.Api.Pushbullet\Ombi.Api.Pushbullet.csproj", "{E237CDF6-D044-437D-B157-E9A3CC0BCF53}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Slack", "Ombi.Api.Slack\Ombi.Api.Slack.csproj", "{71708256-9152-4E81-9FCA-E3181A185806}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -179,6 +181,10 @@ Global {E237CDF6-D044-437D-B157-E9A3CC0BCF53}.Debug|Any CPU.Build.0 = Debug|Any CPU {E237CDF6-D044-437D-B157-E9A3CC0BCF53}.Release|Any CPU.ActiveCfg = Release|Any CPU {E237CDF6-D044-437D-B157-E9A3CC0BCF53}.Release|Any CPU.Build.0 = Release|Any CPU + {71708256-9152-4E81-9FCA-E3181A185806}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71708256-9152-4E81-9FCA-E3181A185806}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71708256-9152-4E81-9FCA-E3181A185806}.Release|Any CPU.ActiveCfg = Release|Any CPU + {71708256-9152-4E81-9FCA-E3181A185806}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -203,5 +209,6 @@ Global {A0892896-F5BD-47E2-823E-DFCE82514EEC} = {9293CA11-360A-4C20-A674-B9E794431BF5} {FD947E63-A0D2-4878-8378-2005D5E9AB8A} = {9293CA11-360A-4C20-A674-B9E794431BF5} {E237CDF6-D044-437D-B157-E9A3CC0BCF53} = {9293CA11-360A-4C20-A674-B9E794431BF5} + {71708256-9152-4E81-9FCA-E3181A185806} = {9293CA11-360A-4C20-A674-B9E794431BF5} EndGlobalSection EndGlobal diff --git a/src/Ombi/ClientApp/app/interfaces/INotifcationSettings.ts b/src/Ombi/ClientApp/app/interfaces/INotifcationSettings.ts index 8037bf5d8..18a4aa9ac 100644 --- a/src/Ombi/ClientApp/app/interfaces/INotifcationSettings.ts +++ b/src/Ombi/ClientApp/app/interfaces/INotifcationSettings.ts @@ -44,12 +44,21 @@ export enum NotificationType { ItemAddedToFaultQueue } -export interface IDiscordNotifcationSettings extends INotificationSettings{ - webhookUrl : string, +export interface IDiscordNotifcationSettings extends INotificationSettings { + webhookUrl: string, username: string, notificationTemplates: INotificationTemplates[], } +export interface ISlackNotificationSettings extends INotificationSettings { + webhookUrl: string, + username: string, + channel: string, + iconEmoji: string, + iconUrl:string + notificationTemplates: INotificationTemplates[], +} + export interface IPushbulletNotificationSettings extends INotificationSettings { accessToken: string, notificationTemplates: INotificationTemplates[], diff --git a/src/Ombi/ClientApp/app/services/applications/tester.service.ts b/src/Ombi/ClientApp/app/services/applications/tester.service.ts index d1dcfe7f9..cdce6a72a 100644 --- a/src/Ombi/ClientApp/app/services/applications/tester.service.ts +++ b/src/Ombi/ClientApp/app/services/applications/tester.service.ts @@ -4,7 +4,12 @@ import { Observable } from 'rxjs/Rx'; import { ServiceAuthHelpers } from '../service.helpers'; -import { IDiscordNotifcationSettings, IEmailNotificationSettings, IPushbulletNotificationSettings } from '../../interfaces/INotifcationSettings' +import { + IDiscordNotifcationSettings, + IEmailNotificationSettings, + IPushbulletNotificationSettings, + ISlackNotificationSettings +} from '../../interfaces/INotifcationSettings' @Injectable() @@ -21,6 +26,10 @@ export class TesterService extends ServiceAuthHelpers { return this.http.post(`${this.url}pushbullet`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData); } + slackTest(settings: ISlackNotificationSettings): Observable { + return this.http.post(`${this.url}slack`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData); + } + emailTest(settings: IEmailNotificationSettings): Observable { return this.http.post(`${this.url}email`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData); } diff --git a/src/Ombi/ClientApp/app/services/settings.service.ts b/src/Ombi/ClientApp/app/services/settings.service.ts index e53dac55f..bc4aa9afa 100644 --- a/src/Ombi/ClientApp/app/services/settings.service.ts +++ b/src/Ombi/ClientApp/app/services/settings.service.ts @@ -13,7 +13,12 @@ import { ICustomizationSettings, IRadarrSettings } from '../interfaces/ISettings'; -import { IEmailNotificationSettings, IDiscordNotifcationSettings, IPushbulletNotificationSettings } from '../interfaces/INotifcationSettings'; +import { + IEmailNotificationSettings, + IDiscordNotifcationSettings, + IPushbulletNotificationSettings, + ISlackNotificationSettings +} from '../interfaces/INotifcationSettings'; @Injectable() export class SettingsService extends ServiceAuthHelpers { @@ -103,4 +108,12 @@ export class SettingsService extends ServiceAuthHelpers { savePushbulletNotificationSettings(settings: IPushbulletNotificationSettings): Observable { return this.httpAuth.post(`${this.url}/notifications/pushbullet`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData).catch(this.handleError) } + + getSlackNotificationSettings(): Observable { + return this.httpAuth.get(`${this.url}/notifications/slack`).map(this.extractData).catch(this.handleError) + } + + saveSlackNotificationSettings(settings: ISlackNotificationSettings): Observable { + return this.httpAuth.post(`${this.url}/notifications/slack`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData).catch(this.handleError) + } } \ No newline at end of file diff --git a/src/Ombi/ClientApp/app/settings/notifications/slack.component.html b/src/Ombi/ClientApp/app/settings/notifications/slack.component.html new file mode 100644 index 000000000..be4504722 --- /dev/null +++ b/src/Ombi/ClientApp/app/settings/notifications/slack.component.html @@ -0,0 +1,84 @@ + + +
+
+ Slack Notifications +
+
+ +
+ +
+ + +
+
+ +
+
The Webhook Url is required
+
+ +
+ + +
+ + Click Here and follow the guide. You will then have a Webhook Url + +
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+ + You can find more details about the Slack API Here + + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+ + +
+ +
+
+
\ No newline at end of file diff --git a/src/Ombi/ClientApp/app/settings/notifications/slack.component.ts b/src/Ombi/ClientApp/app/settings/notifications/slack.component.ts new file mode 100644 index 000000000..c182859c2 --- /dev/null +++ b/src/Ombi/ClientApp/app/settings/notifications/slack.component.ts @@ -0,0 +1,85 @@ +import { Component, OnInit } from '@angular/core'; +import { FormGroup, Validators, FormBuilder } from '@angular/forms'; + +import { INotificationTemplates, ISlackNotificationSettings, NotificationType } from '../../interfaces/INotifcationSettings'; +import { SettingsService } from '../../services/settings.service'; +import { NotificationService } from "../../services/notification.service"; +import { TesterService } from "../../services/applications/tester.service"; + +@Component({ + templateUrl: './slack.component.html', +}) +export class SlackComponent implements OnInit { + constructor(private settingsService: SettingsService, + private notificationService: NotificationService, + private fb: FormBuilder, + private testerService : TesterService) { } + + NotificationType = NotificationType; + templates: INotificationTemplates[]; + + form: FormGroup; + + ngOnInit(): void { + this.settingsService.getSlackNotificationSettings().subscribe(x => { + this.templates = x.notificationTemplates; + + this.form = this.fb.group({ + enabled: [x.enabled], + username: [x.username], + webhookUrl: [x.webhookUrl, [Validators.required]], + iconEmoji: [x.iconEmoji], + iconUrl: [x.iconUrl], + channel: [x.channel] + + }); + }); + } + + onSubmit(form: FormGroup) { + if (form.invalid) { + this.notificationService.error("Validation", "Please check your entered values"); + return + } + + + var settings = form.value; + if (settings.iconEmoji && settings.iconUrl) { + + this.notificationService.error("Validation", "You cannot have a Emoji icon and a URL icon"); + return; + } + settings.notificationTemplates = this.templates; + + this.settingsService.saveSlackNotificationSettings(settings).subscribe(x => { + if (x) { + this.notificationService.success("Settings Saved", "Successfully saved the Slack settings"); + } else { + this.notificationService.success("Settings Saved", "There was an error when saving the Slack settings"); + } + }); + + } + + test(form: FormGroup) { + if (form.invalid) { + this.notificationService.error("Validation", "Please check your entered values"); + return + } + + var settings = form.value; + if (settings.iconEmoji && settings.iconUrl) { + + this.notificationService.error("Validation", "You cannot have a Emoji icon and a URL icon"); + return; + } + this.testerService.slackTest(settings).subscribe(x => { + if (x) { + this.notificationService.success("Successful", "Successfully sent a Slack message, please check the discord channel"); + } else { + this.notificationService.success("Error", "There was an error when sending the Slack message. Please check your settings"); + } + }) + + } +} \ No newline at end of file diff --git a/src/Ombi/ClientApp/app/settings/settings.module.ts b/src/Ombi/ClientApp/app/settings/settings.module.ts index 6d168b665..f825a3cc0 100644 --- a/src/Ombi/ClientApp/app/settings/settings.module.ts +++ b/src/Ombi/ClientApp/app/settings/settings.module.ts @@ -21,6 +21,7 @@ import { LandingPageComponent } from './landingpage/landingpage.component'; import { CustomizationComponent } from './customization/customization.component'; import { EmailNotificationComponent } from './notifications/emailnotification.component'; import { DiscordComponent } from './notifications/discord.component'; +import { SlackComponent } from './notifications/slack.component'; import { NotificationTemplate } from './notifications/notificationtemplate.component'; import { SettingsMenuComponent } from './settingsmenu.component'; @@ -38,6 +39,7 @@ const routes: Routes = [ { path: 'Settings/Customization', component: CustomizationComponent, canActivate: [AuthGuard] }, { path: 'Settings/Email', component: EmailNotificationComponent, canActivate: [AuthGuard] }, { path: 'Settings/Discord', component: DiscordComponent, canActivate: [AuthGuard] }, + { path: 'Settings/Slack', component: SlackComponent, canActivate: [AuthGuard] }, ]; @NgModule({ @@ -65,6 +67,7 @@ const routes: Routes = [ CustomizationComponent, DiscordComponent, SonarrComponent, + SlackComponent, RadarrComponent, EmailNotificationComponent, HumanizePipe, diff --git a/src/Ombi/ClientApp/app/settings/settingsmenu.component.html b/src/Ombi/ClientApp/app/settings/settingsmenu.component.html index 25125879d..3982acc54 100644 --- a/src/Ombi/ClientApp/app/settings/settingsmenu.component.html +++ b/src/Ombi/ClientApp/app/settings/settingsmenu.component.html @@ -45,6 +45,7 @@
  • Email
  • Discord
  • +
  • Discord
  • Pushbullet
  • Pushover
  • diff --git a/src/Ombi/Controllers/External/TesterController.cs b/src/Ombi/Controllers/External/TesterController.cs index b210de871..c4ad1a517 100644 --- a/src/Ombi/Controllers/External/TesterController.cs +++ b/src/Ombi/Controllers/External/TesterController.cs @@ -24,19 +24,23 @@ namespace Ombi.Controllers.External /// The service. /// The notification. /// The notification. + /// The pushbullet. + /// The slack. public TesterController(INotificationService service, IDiscordNotification notification, IEmailNotification emailN, - IPushbulletNotification pushbullet) + IPushbulletNotification pushbullet, ISlackNotification slack) { Service = service; DiscordNotification = notification; EmailNotification = emailN; PushbulletNotification = pushbullet; + SlackNotification = slack; } private INotificationService Service { get; } private IDiscordNotification DiscordNotification { get; } private IEmailNotification EmailNotification { get; } private IPushbulletNotification PushbulletNotification { get; } + private ISlackNotification SlackNotification { get; } /// @@ -52,10 +56,10 @@ namespace Ombi.Controllers.External new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); return true; - } - + } + /// - /// Sends a test message to discord using the provided settings + /// Sends a test message to Pushbullet using the provided settings /// /// The settings. /// @@ -69,6 +73,22 @@ namespace Ombi.Controllers.External return true; } + + /// + /// Sends a test message to Slack using the provided settings + /// + /// The settings. + /// + [HttpPost("slack")] + public bool Slack([FromBody] SlackNotificationSettings settings) + { + settings.Enabled = true; + SlackNotification.NotifyAsync( + new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); + + return true; + } + /// /// Sends a test message via email to the admin email using the provided settings /// diff --git a/src/Ombi/Controllers/SettingsController.cs b/src/Ombi/Controllers/SettingsController.cs index bbe56360c..f53d1645b 100644 --- a/src/Ombi/Controllers/SettingsController.cs +++ b/src/Ombi/Controllers/SettingsController.cs @@ -295,6 +295,41 @@ namespace Ombi.Controllers return model; } + + /// + /// Saves the slack notification settings. + /// + /// The model. + /// + [HttpPost("notifications/slack")] + public async Task SlacktNotificationSettings([FromBody] SlackNotificationsViewModel 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; + } + + /// + /// Gets the slack Notification Settings. + /// + /// + [HttpGet("notifications/slack")] + public async Task SlackNotificationSettings() + { + var settings = await Get(); + var model = Mapper.Map(settings); + + // Lookup to see if we have any templates saved + model.NotificationTemplates = await BuildTemplates(NotificationAgent.Slack); + + return model; + } + private async Task> BuildTemplates(NotificationAgent agent) { var templates = await TemplateRepository.GetAllTemplates(agent); diff --git a/src/Ombi/Ombi.csproj b/src/Ombi/Ombi.csproj index 12edbab93..b7a20b914 100644 --- a/src/Ombi/Ombi.csproj +++ b/src/Ombi/Ombi.csproj @@ -76,5 +76,11 @@ + + + + slack.component.ts + +