diff --git a/src/.vscode/settings.json b/src/.vscode/settings.json new file mode 100644 index 000000000..a3948377f --- /dev/null +++ b/src/.vscode/settings.json @@ -0,0 +1,11 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.exclude": { + "**/.git": true, + "**/.svn": true, + "**/.hg": true, + "**/.DS_Store": true, + "**/*.js": {"when": "$(basename).ts"}, // Hide JS files when there is a ts file + "**/*.js.map" : true + } +} \ No newline at end of file diff --git a/src/Ombi.Api.Discord/DiscordApi.cs b/src/Ombi.Api.Discord/DiscordApi.cs index 537bf15ef..3acd717ad 100644 --- a/src/Ombi.Api.Discord/DiscordApi.cs +++ b/src/Ombi.Api.Discord/DiscordApi.cs @@ -14,15 +14,10 @@ namespace Ombi.Api.Discord private string Endpoint => "https://discordapp.com/api/"; //webhooks/270828242636636161/lLysOMhJ96AFO1kvev0bSqP-WCZxKUh1UwfubhIcLkpS0DtM3cg4Pgeraw3waoTXbZii private Api Api { get; } - public async Task SendMessage(string message, string webhookId, string webhookToken, string username = null) + public async Task SendMessage(DiscordWebhookBody body, string webhookId, string webhookToken) { var request = new Request(Endpoint, $"webhooks/{webhookId}/{webhookToken}", HttpMethod.Post); - var body = new DiscordWebhookBody - { - content = message, - username = username - }; request.AddJsonBody(body); request.AddHeader("Content-Type", "application/json"); diff --git a/src/Ombi.Api.Discord/IDiscordApi.cs b/src/Ombi.Api.Discord/IDiscordApi.cs index 2a5375ee2..19bc05bc6 100644 --- a/src/Ombi.Api.Discord/IDiscordApi.cs +++ b/src/Ombi.Api.Discord/IDiscordApi.cs @@ -1,9 +1,10 @@ using System.Threading.Tasks; +using Ombi.Api.Discord.Models; namespace Ombi.Api.Discord { public interface IDiscordApi { - Task SendMessage(string message, string webhookId, string webhookToken, string username = null); + Task SendMessage(DiscordWebhookBody body, string webhookId, string webhookToken); } } \ No newline at end of file diff --git a/src/Ombi.Api.Discord/Models/DiscordWebhookBody.cs b/src/Ombi.Api.Discord/Models/DiscordWebhookBody.cs index a80423a84..2d74087fb 100644 --- a/src/Ombi.Api.Discord/Models/DiscordWebhookBody.cs +++ b/src/Ombi.Api.Discord/Models/DiscordWebhookBody.cs @@ -1,8 +1,24 @@ -namespace Ombi.Api.Discord.Models +using System.Collections.Generic; + +namespace Ombi.Api.Discord.Models { public class DiscordWebhookBody { public string content { get; set; } public string username { get; set; } + public List embeds { get; set; } + } + + public class DiscordEmbeds + { + public string title { get; set; } + public string type => "rich"; // Always rich or embedded content + public string description { get; set; } // Don't really need to set this + public DiscordImage image { get; set; } + } + + public class DiscordImage + { + public string url { get; set; } } } \ No newline at end of file diff --git a/src/Ombi.Core/Models/UI/DiscordNotificationsViewModel.cs b/src/Ombi.Core/Models/UI/DiscordNotificationsViewModel.cs new file mode 100644 index 000000000..a9185588a --- /dev/null +++ b/src/Ombi.Core/Models/UI/DiscordNotificationsViewModel.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 DiscordNotificationsViewModel : DiscordNotificationSettings + { + /// + /// Gets or sets the notification templates. + /// + /// + /// The notification templates. + /// + public List NotificationTemplates { get; set; } + } +} diff --git a/src/Ombi.Core/Models/UI/EmailNotificationsViewModel.cs b/src/Ombi.Core/Models/UI/EmailNotificationsViewModel.cs index 1a71c95c5..3e2e22af7 100644 --- a/src/Ombi.Core/Models/UI/EmailNotificationsViewModel.cs +++ b/src/Ombi.Core/Models/UI/EmailNotificationsViewModel.cs @@ -2,7 +2,7 @@ using Ombi.Settings.Settings.Models.Notifications; using Ombi.Store.Entities; -namespace Ombi.Models.Notifications +namespace Ombi.Core.Models.UI { /// /// The view model for the notification settings page diff --git a/src/Ombi.DependencyInjection/IocExtensions.cs b/src/Ombi.DependencyInjection/IocExtensions.cs index 228d60b8d..54130b57c 100644 --- a/src/Ombi.DependencyInjection/IocExtensions.cs +++ b/src/Ombi.DependencyInjection/IocExtensions.cs @@ -27,6 +27,7 @@ using Ombi.Settings.Settings; using Ombi.Store.Context; using Ombi.Store.Repository; using Ombi.Core.Rules; +using Ombi.Notifications.Agents; using Ombi.Schedule.Jobs.Radarr; namespace Ombi.DependencyInjection @@ -84,7 +85,11 @@ namespace Ombi.DependencyInjection services.AddTransient(); services.AddTransient(typeof(IRequestService<>), typeof(JsonRequestService<>)); services.AddSingleton(); - services.AddSingleton(); + services.AddTransient(); + + + services.AddTransient(); + services.AddTransient(); } public static void RegisterJobs(this IServiceCollection services) diff --git a/src/Ombi.Mapping/Profiles/SettingsProfile.cs b/src/Ombi.Mapping/Profiles/SettingsProfile.cs index c75c16f81..1633ea35b 100644 --- a/src/Ombi.Mapping/Profiles/SettingsProfile.cs +++ b/src/Ombi.Mapping/Profiles/SettingsProfile.cs @@ -1,5 +1,5 @@ using AutoMapper; -using Ombi.Models.Notifications; +using Ombi.Core.Models.UI; using Ombi.Settings.Settings.Models.Notifications; namespace Ombi.Mapping.Profiles @@ -9,6 +9,7 @@ namespace Ombi.Mapping.Profiles public SettingsProfile() { CreateMap().ReverseMap(); + CreateMap().ReverseMap(); } } } \ No newline at end of file diff --git a/src/Ombi.Notifications/Agents/DiscordNotification.cs b/src/Ombi.Notifications/Agents/DiscordNotification.cs index f3e94c3b3..421211b27 100644 --- a/src/Ombi.Notifications/Agents/DiscordNotification.cs +++ b/src/Ombi.Notifications/Agents/DiscordNotification.cs @@ -1,16 +1,19 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Ombi.Api.Discord; +using Ombi.Api.Discord.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.Repository; namespace Ombi.Notifications.Agents { - public class DiscordNotification : BaseNotification + public class DiscordNotification : BaseNotification, IDiscordNotification { public DiscordNotification(IDiscordApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r) : base(sn, r) { @@ -47,21 +50,22 @@ namespace Ombi.Notifications.Agents protected override async Task NewRequest(NotificationOptions model, DiscordNotificationSettings settings) { - var message = $"{model.Title} has been requested by user: {model.RequestedUser}"; + var template = await TemplateRepository.GetTemplate(NotificationAgent.Email, NotificationType.NewRequest); var notification = new NotificationMessage { - Message = message, + Message = template.Message, }; await Send(notification, settings); } protected override async Task Issue(NotificationOptions model, DiscordNotificationSettings settings) { - var message = $"A new issue: {model.Body} has been reported by user: {model.RequestedUser} for the title: {model.Title}"; + var template = await TemplateRepository.GetTemplate(NotificationAgent.Email, NotificationType.Issue); + var notification = new NotificationMessage { - Message = message, + Message = template.Message, }; await Send(notification, settings); } @@ -71,37 +75,41 @@ namespace Ombi.Notifications.Agents var message = $"Hello! The user '{model.RequestedUser}' has requested {model.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, + Message = message }; + notification.Other.Add("image", model.ImgSrc); await Send(notification, settings); } protected override async Task RequestDeclined(NotificationOptions model, DiscordNotificationSettings settings) { - var message = $"Hello! Your request for {model.Title} has been declined, Sorry!"; + var template = await TemplateRepository.GetTemplate(NotificationAgent.Email, NotificationType.RequestDeclined); + var notification = new NotificationMessage { - Message = message, + Message = template.Message, }; await Send(notification, settings); } protected override async Task RequestApproved(NotificationOptions model, DiscordNotificationSettings settings) { - var message = $"Hello! The request for {model.Title} has now been approved!"; + var template = await TemplateRepository.GetTemplate(NotificationAgent.Email, NotificationType.RequestApproved); + var notification = new NotificationMessage { - Message = message, + Message = template.Message, }; await Send(notification, settings); } protected override async Task AvailableRequest(NotificationOptions model, DiscordNotificationSettings settings) { - var message = $"Hello! The request for {model.Title} is now available!"; + var template = await TemplateRepository.GetTemplate(NotificationAgent.Email, NotificationType.RequestAvailable); + var notification = new NotificationMessage { - Message = message, + Message = template.Message, }; await Send(notification, settings); } @@ -110,7 +118,28 @@ namespace Ombi.Notifications.Agents { try { - await Api.SendMessage(model.Message, settings.WebookId, settings.Token, settings.Username); + var discordBody = new DiscordWebhookBody + { + content = model.Message, + username = settings.Username, + }; + + string image; + if (model.Other.TryGetValue("image", out image)) + { + discordBody.embeds = new List + { + new DiscordEmbeds + { + image = new DiscordImage + { + url = image + } + } + }; + } + + await Api.SendMessage(discordBody, settings.WebookId, settings.Token); } catch (Exception e) { diff --git a/src/Ombi.Notifications/Agents/EmailNotification.cs b/src/Ombi.Notifications/Agents/EmailNotification.cs index 0648494ce..07f253d56 100644 --- a/src/Ombi.Notifications/Agents/EmailNotification.cs +++ b/src/Ombi.Notifications/Agents/EmailNotification.cs @@ -4,6 +4,7 @@ using MailKit.Net.Smtp; using MimeKit; using Ombi.Core.Settings; using Ombi.Helpers; +using Ombi.Notifications.Interfaces; using Ombi.Notifications.Models; using Ombi.Notifications.Templates; using Ombi.Settings.Settings.Models.Notifications; @@ -11,7 +12,7 @@ using Ombi.Store.Repository; namespace Ombi.Notifications.Agents { - public class EmailNotification : BaseNotification + public class EmailNotification : BaseNotification, IEmailNotification { public EmailNotification(ISettingsService settings, INotificationTemplatesRepository r) : base(settings, r) { diff --git a/src/Ombi.Notifications/Agents/IDiscordNotification.cs b/src/Ombi.Notifications/Agents/IDiscordNotification.cs new file mode 100644 index 000000000..64577fc11 --- /dev/null +++ b/src/Ombi.Notifications/Agents/IDiscordNotification.cs @@ -0,0 +1,6 @@ +namespace Ombi.Notifications.Agents +{ + public interface IDiscordNotification : INotification + { + } +} \ No newline at end of file diff --git a/src/Ombi.Notifications/Agents/IEmailNotification.cs b/src/Ombi.Notifications/Agents/IEmailNotification.cs new file mode 100644 index 000000000..6ed511b41 --- /dev/null +++ b/src/Ombi.Notifications/Agents/IEmailNotification.cs @@ -0,0 +1,6 @@ +namespace Ombi.Notifications.Agents +{ + public interface IEmailNotification : INotification + { + } +} \ No newline at end of file diff --git a/src/Ombi.Notifications/Interfaces/BaseNotification.cs b/src/Ombi.Notifications/Interfaces/BaseNotification.cs index 8b2bfec24..00f74d099 100644 --- a/src/Ombi.Notifications/Interfaces/BaseNotification.cs +++ b/src/Ombi.Notifications/Interfaces/BaseNotification.cs @@ -1,15 +1,11 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Ombi.Core.Settings; using Ombi.Helpers; using Ombi.Notifications.Models; -using Ombi.Store; -using Ombi.Store.Entities; using Ombi.Store.Repository; -namespace Ombi.Notifications +namespace Ombi.Notifications.Interfaces { public abstract class BaseNotification : INotification where T : Settings.Settings.Models.Settings, new() { diff --git a/src/Ombi/ClientApp/app/interfaces/INotifcationSettings.ts b/src/Ombi/ClientApp/app/interfaces/INotifcationSettings.ts index 11c134055..8bd1ec507 100644 --- a/src/Ombi/ClientApp/app/interfaces/INotifcationSettings.ts +++ b/src/Ombi/ClientApp/app/interfaces/INotifcationSettings.ts @@ -46,28 +46,6 @@ export enum NotificationType { export interface IDiscordNotifcationSettings extends INotificationSettings{ webhookUrl : string, - username : string, - - - // public string WebhookUrl { get; set; } - // public string Username { get; set; } - - // [JsonIgnore] - // public string WebookId => SplitWebUrl(4); - - // [JsonIgnore] - // public string Token => SplitWebUrl(5); - - // private string SplitWebUrl(int index) - // { - // if (!WebhookUrl.StartsWith("http", StringComparison.InvariantCulture)) - // { - // WebhookUrl = "https://" + WebhookUrl; - // } - // var split = WebhookUrl.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); - - // return split.Length < index - // ? string.Empty - // : split[index]; - // } + username: string, + notificationTemplates: INotificationTemplates[], } \ No newline at end of file diff --git a/src/Ombi/ClientApp/app/request-grid/request-card.component.html b/src/Ombi/ClientApp/app/request-grid/request-card.component.html index dd03b381a..f51a9f898 100644 --- a/src/Ombi/ClientApp/app/request-grid/request-card.component.html +++ b/src/Ombi/ClientApp/app/request-grid/request-card.component.html @@ -1,3 +1,45 @@ -
- {{request.title}} + + +
+
+ poster +
+
+ {{request.title}} +
\ No newline at end of file diff --git a/src/Ombi/ClientApp/app/request-grid/request-grid.component.html b/src/Ombi/ClientApp/app/request-grid/request-grid.component.html index ff0b1b2a2..eecd799ed 100644 --- a/src/Ombi/ClientApp/app/request-grid/request-grid.component.html +++ b/src/Ombi/ClientApp/app/request-grid/request-grid.component.html @@ -1,7 +1,6 @@ 
+

New Requests

- Title -
-
-
- +
+
+

Approved Requests

- -
-
-
+
+

Available

- Title -
-
-
-
- -
+
+
diff --git a/src/Ombi/ClientApp/app/services/applications/tester.service.ts b/src/Ombi/ClientApp/app/services/applications/tester.service.ts new file mode 100644 index 000000000..1345f72c7 --- /dev/null +++ b/src/Ombi/ClientApp/app/services/applications/tester.service.ts @@ -0,0 +1,23 @@ +import { Injectable } from '@angular/core'; +import { AuthHttp } from 'angular2-jwt'; +import { Observable } from 'rxjs/Rx'; + +import { ServiceAuthHelpers } from '../service.helpers'; + +import { IDiscordNotifcationSettings, IEmailNotificationSettings } from '../../interfaces/INotifcationSettings' + + +@Injectable() +export class TesterService extends ServiceAuthHelpers { + constructor(http: AuthHttp) { + super(http, '/api/v1/tester/'); + } + + discordTest(settings: IDiscordNotifcationSettings): Observable { + return this.http.post(`${this.url}discord`, 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); + } +} \ No newline at end of file diff --git a/src/Ombi/ClientApp/app/services/settings.service.ts b/src/Ombi/ClientApp/app/services/settings.service.ts index 3d389b052..bdaf20e40 100644 --- a/src/Ombi/ClientApp/app/services/settings.service.ts +++ b/src/Ombi/ClientApp/app/services/settings.service.ts @@ -13,7 +13,7 @@ import { ICustomizationSettings, IRadarrSettings } from '../interfaces/ISettings'; -import { IEmailNotificationSettings } from '../interfaces/INotifcationSettings'; +import { IEmailNotificationSettings, IDiscordNotifcationSettings } from '../interfaces/INotifcationSettings'; @Injectable() export class SettingsService extends ServiceAuthHelpers { @@ -88,4 +88,12 @@ export class SettingsService extends ServiceAuthHelpers { saveEmailNotificationSettings(settings: IEmailNotificationSettings): Observable { return this.httpAuth.post(`${this.url}/notifications/email`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData).catch(this.handleError) } + + getDiscordNotificationSettings(): Observable { + return this.httpAuth.get(`${this.url}/notifications/discord`).map(this.extractData).catch(this.handleError) + } + + saveDiscordNotificationSettings(settings: IDiscordNotifcationSettings): Observable { + return this.httpAuth.post(`${this.url}/notifications/discord`, 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/discord.component.html b/src/Ombi/ClientApp/app/settings/notifications/discord.component.html index 20582e666..9b646e1eb 100644 --- a/src/Ombi/ClientApp/app/settings/notifications/discord.component.html +++ b/src/Ombi/ClientApp/app/settings/notifications/discord.component.html @@ -1,10 +1,10 @@  -
+
- Email Notifications + Discord Notifications
-
+
@@ -13,68 +13,29 @@
-
-
- -
-
-
-
Host is required
-
The Port is required
-
The Email Sender is required
-
The Email Sender needs to be a valid email address
-
The Email Sender is required
-
The Admin Email needs to be a valid email address
-
The Username is required
-
The Password is required
-
- -
- -
- -
-
- -
- -
- -
+
+
The Webhook Url is required
- +
- +
- -
- -
-
- - -
- +
-
- -
- -
-
+
- @@ -85,7 +46,7 @@
- +
diff --git a/src/Ombi/ClientApp/app/settings/notifications/discord.component.ts b/src/Ombi/ClientApp/app/settings/notifications/discord.component.ts index 0d3d217d3..5c0da58e3 100644 --- a/src/Ombi/ClientApp/app/settings/notifications/discord.component.ts +++ b/src/Ombi/ClientApp/app/settings/notifications/discord.component.ts @@ -1,10 +1,10 @@ import { Component, OnInit } from '@angular/core'; import { FormGroup, Validators, FormBuilder } from '@angular/forms'; -import { INotificationTemplates, IEmailNotificationSettings, NotificationType } from '../../interfaces/INotifcationSettings'; +import { INotificationTemplates, IDiscordNotifcationSettings, NotificationType } from '../../interfaces/INotifcationSettings'; import { SettingsService } from '../../services/settings.service'; import { NotificationService } from "../../services/notification.service"; -import { ValidationService } from "../../services/helpers/validation.service"; +import { TesterService } from "../../services/applications/tester.service"; @Component({ templateUrl: './discord.component.html', @@ -13,75 +13,58 @@ export class DiscordComponent implements OnInit { constructor(private settingsService: SettingsService, private notificationService: NotificationService, private fb: FormBuilder, - private validationService: ValidationService) { } + private testerService : TesterService) { } NotificationType = NotificationType; templates: INotificationTemplates[]; - emailForm: FormGroup; + form: FormGroup; ngOnInit(): void { - this.settingsService.getEmailNotificationSettings().subscribe(x => { + this.settingsService.getDiscordNotificationSettings().subscribe(x => { this.templates = x.notificationTemplates; - this.emailForm = this.fb.group({ + this.form = this.fb.group({ enabled: [x.enabled], - authentication: [x.authentication], - host: [x.host, [Validators.required]], - password: [x.password], - port: [x.port, [Validators.required]], - sender: [x.sender, [Validators.required, Validators.email]], username: [x.username], - adminEmail: [x.adminEmail, [Validators.required, Validators.email]], - }); - - if (x.authentication) { - this.validationService.enableValidation(this.emailForm, 'username'); - this.validationService.enableValidation(this.emailForm, 'password'); - } + webhookUrl: [x.webhookUrl, [Validators.required]], - this.subscribeToAuthChanges(); + }); }); } onSubmit(form: FormGroup) { - console.log(form.value, form.valid); - if (form.invalid) { this.notificationService.error("Validation", "Please check your entered values"); return } - var settings = form.value; + var settings = form.value; settings.notificationTemplates = this.templates; - this.settingsService.saveEmailNotificationSettings(settings).subscribe(x => { + this.settingsService.saveDiscordNotificationSettings(settings).subscribe(x => { if (x) { - this.notificationService.success("Settings Saved", "Successfully saved Email settings"); + this.notificationService.success("Settings Saved", "Successfully saved the Discord settings"); } else { - this.notificationService.success("Settings Saved", "There was an error when saving the Email settings"); + this.notificationService.success("Settings Saved", "There was an error when saving the Discord settings"); } }); } - save() { - - } - - private subscribeToAuthChanges() { - const authCtrl = this.emailForm.controls.authentication; - const changes$ = authCtrl.valueChanges; - - changes$.subscribe((auth: boolean) => { + test(form: FormGroup) { + if (form.invalid) { + this.notificationService.error("Validation", "Please check your entered values"); + return + } - if (auth) { - this.validationService.enableValidation(this.emailForm, 'username'); - this.validationService.enableValidation(this.emailForm, 'password'); + this.testerService.discordTest(form.value).subscribex(x => { + if (x) { + this.notificationService.success("Successful", "Successfully sent a Discord message, please check the discord channel"); } else { - this.validationService.disableValidation(this.emailForm, 'username'); - this.validationService.disableValidation(this.emailForm, 'password'); + this.notificationService.success("Error", "There was an error when sending the Discord message. Please check your settings"); } - }); + }) + } } \ No newline at end of file diff --git a/src/Ombi/ClientApp/app/settings/notifications/emailnotification.component.html b/src/Ombi/ClientApp/app/settings/notifications/emailnotification.component.html index 20582e666..cef2acf38 100644 --- a/src/Ombi/ClientApp/app/settings/notifications/emailnotification.component.html +++ b/src/Ombi/ClientApp/app/settings/notifications/emailnotification.component.html @@ -74,7 +74,7 @@
- diff --git a/src/Ombi/ClientApp/app/settings/notifications/emailnotification.component.ts b/src/Ombi/ClientApp/app/settings/notifications/emailnotification.component.ts index 6977f8a55..ac292da05 100644 --- a/src/Ombi/ClientApp/app/settings/notifications/emailnotification.component.ts +++ b/src/Ombi/ClientApp/app/settings/notifications/emailnotification.component.ts @@ -4,6 +4,7 @@ import { FormGroup, Validators, FormBuilder } from '@angular/forms'; import { INotificationTemplates, IEmailNotificationSettings, NotificationType } from '../../interfaces/INotifcationSettings'; import { SettingsService } from '../../services/settings.service'; import { NotificationService } from "../../services/notification.service"; +import { TesterService } from "../../services/applications/tester.service"; import { ValidationService } from "../../services/helpers/validation.service"; @Component({ @@ -13,7 +14,8 @@ export class EmailNotificationComponent implements OnInit { constructor(private settingsService: SettingsService, private notificationService: NotificationService, private fb: FormBuilder, - private validationService: ValidationService) { } + private validationService: ValidationService, + private testerService: TesterService) { } NotificationType = NotificationType; templates: INotificationTemplates[]; @@ -45,8 +47,6 @@ export class EmailNotificationComponent implements OnInit { } onSubmit(form: FormGroup) { - console.log(form.value, form.valid); - if (form.invalid) { this.notificationService.error("Validation", "Please check your entered values"); return @@ -65,8 +65,19 @@ export class EmailNotificationComponent implements OnInit { } - save() { + test(form: FormGroup) { + if (form.invalid) { + this.notificationService.error("Validation", "Please check your entered values"); + return + } + this.testerService.emailTest(form.value).subscribe(x => { + if (x) { + this.notificationService.success("Sent", "Successfully sent an email message, please check your inbox"); + } else { + this.notificationService.success("Error", "There was an error when sending the Email message, please check your settings."); + } + }) } private subscribeToAuthChanges() { diff --git a/src/Ombi/ClientApp/app/settings/settings.module.ts b/src/Ombi/ClientApp/app/settings/settings.module.ts index 4bb9b2568..3e4970943 100644 --- a/src/Ombi/ClientApp/app/settings/settings.module.ts +++ b/src/Ombi/ClientApp/app/settings/settings.module.ts @@ -9,6 +9,7 @@ import { AuthGuard } from '../auth/auth.guard'; import { AuthModule } from '../auth/auth.module'; import { SonarrService } from '../services/applications/sonarr.service'; import { RadarrService } from '../services/applications/radarr.service'; +import { TesterService } from '../services/applications/tester.service'; import { ValidationService } from '../services/helpers/validation.service'; import { OmbiComponent } from './ombi/ombi.component'; @@ -73,7 +74,8 @@ const routes: Routes = [ AuthService, RadarrService, AuthGuard, - ValidationService + ValidationService, + TesterService ], }) diff --git a/src/Ombi/Controllers/External/TesterController.cs b/src/Ombi/Controllers/External/TesterController.cs new file mode 100644 index 000000000..b61c1fb4d --- /dev/null +++ b/src/Ombi/Controllers/External/TesterController.cs @@ -0,0 +1,70 @@ +using System; +using Hangfire; +using Microsoft.AspNetCore.Mvc; +using Ombi.Attributes; +using Ombi.Core.Notifications; +using Ombi.Helpers; +using Ombi.Notifications.Agents; +using Ombi.Notifications.Models; +using Ombi.Settings.Settings.Models.Notifications; + +namespace Ombi.Controllers.External +{ + /// + /// The Tester Controller + /// + /// + [Admin] + public class TesterController : BaseV1ApiController + { + /// + /// Initializes a new instance of the class. + /// + /// The service. + /// The notification. + public TesterController(INotificationService service, IDiscordNotification notification, IEmailNotification emailN) + { + Service = service; + DiscordNotification = notification; + EmailNotification = emailN; + } + + private INotificationService Service { get; } + private IDiscordNotification DiscordNotification { get; } + private IEmailNotification EmailNotification { get; } + + /// + /// Sends a test message to discord using the provided settings + /// + /// The settings. + /// + [HttpPost("discord")] + public bool Discord([FromBody] DiscordNotificationSettings settings) + { + settings.Enabled = true; + BackgroundJob.Enqueue(() => Service.PublishTest(new NotificationOptions{NotificationType = NotificationType.Test}, settings, DiscordNotification)); + + return true; + } + + /// + /// Sends a test message via email to the admin email using the provided settings + /// + /// The settings. + /// + [HttpPost("email")] + public bool Email([FromBody] EmailNotificationSettings settings) + { + settings.Enabled = true; + var notificationModel = new NotificationOptions + { + NotificationType = NotificationType.Test, + DateTime = DateTime.Now, + ImgSrc = "https://imgs.xkcd.com/comics/shouldnt_be_hard.png" + }; + BackgroundJob.Enqueue(() => Service.PublishTest(notificationModel, settings, EmailNotification)); + + return true; + } + } +} \ No newline at end of file diff --git a/src/Ombi/Controllers/SettingsController.cs b/src/Ombi/Controllers/SettingsController.cs index fefbfbd82..03732a78d 100644 --- a/src/Ombi/Controllers/SettingsController.cs +++ b/src/Ombi/Controllers/SettingsController.cs @@ -6,11 +6,11 @@ using AutoMapper; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Ombi.Attributes; +using Ombi.Core.Models.UI; using Ombi.Core.Settings; using Ombi.Core.Settings.Models; using Ombi.Core.Settings.Models.External; using Ombi.Helpers; -using Ombi.Models.Notifications; using Ombi.Settings.Settings.Models; using Ombi.Settings.Settings.Models.External; using Ombi.Settings.Settings.Models.Notifications; @@ -208,41 +208,74 @@ namespace Ombi.Controllers return result; } - - /// - /// Gets the Email Notification Settings. - /// - /// - [HttpGet("notifications/email")] - public async Task EmailNotificationSettings() - { - var emailSettings = await Get(); - var model = Mapper.Map(emailSettings); + /// + /// Gets the Email Notification Settings. + /// + /// + [HttpGet("notifications/email")] + public async Task EmailNotificationSettings() + { + var emailSettings = await Get(); + var model = Mapper.Map(emailSettings); - // Lookup to see if we have any templates saved - model.NotificationTemplates = await BuildTemplates(NotificationAgent.Email); + // Lookup to see if we have any templates saved + model.NotificationTemplates = await BuildTemplates(NotificationAgent.Email); - return model; - } + return model; + } - private async Task> BuildTemplates(NotificationAgent agent) - { - var templates = await TemplateRepository.GetAllTemplates(agent); - return templates.ToList(); - } + /// + /// Saves the discord notification settings. + /// + /// The model. + /// + [HttpPost("notifications/email")] + public async Task DiscordNotificationSettings([FromBody] DiscordNotificationsViewModel model) + { + // Save the email settings + var settings = Mapper.Map(model); + var result = await Save(settings); + // Save the templates + await TemplateRepository.UpdateRange(model.NotificationTemplates); - private async Task Get() - { - var settings = SettingsResolver.Resolve(); - return await settings.GetSettingsAsync(); - } + return result; + } - private async Task Save(T settingsModel) - { - var settings = SettingsResolver.Resolve(); - return await settings.SaveSettingsAsync(settingsModel); + /// + /// Gets the discord Notification Settings. + /// + /// + [HttpGet("notifications/email")] + public async Task DiscordNotificationSettings() + { + var emailSettings = await Get(); + var model = Mapper.Map(emailSettings); + + // Lookup to see if we have any templates saved + model.NotificationTemplates = await BuildTemplates(NotificationAgent.Discord); + + return model; + } + + private async Task> BuildTemplates(NotificationAgent agent) + { + var templates = await TemplateRepository.GetAllTemplates(agent); + return templates.ToList(); + } + + + private async Task Get() + { + var settings = SettingsResolver.Resolve(); + return await settings.GetSettingsAsync(); + } + + private async Task Save(T settingsModel) + { + var settings = SettingsResolver.Resolve(); + return await settings.SaveSettingsAsync(settingsModel); + } } } -} diff --git a/src/Ombi/Styles/_imports.scss b/src/Ombi/Styles/_imports.scss index 75792bef5..14954d834 100644 --- a/src/Ombi/Styles/_imports.scss +++ b/src/Ombi/Styles/_imports.scss @@ -6,4 +6,5 @@ @import "../bower_components/font-awesome/scss/font-awesome.scss";*/ @import '../bootstrap.css'; -@import './Styles.scss'; \ No newline at end of file +@import './Styles.scss'; +@import '_loading.scss'; \ No newline at end of file diff --git a/src/Ombi/Styles/_loading.scss b/src/Ombi/Styles/_loading.scss new file mode 100644 index 000000000..3febd61fc --- /dev/null +++ b/src/Ombi/Styles/_loading.scss @@ -0,0 +1,69 @@ +.app-loading-container { + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -webkit-box-pack: center; + -webkit-box-align: center; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + + .app-loading { + margin: auto; + font-size: 2em; + } + + .app-loading-one { + opacity: 0; + -webkit-animation: dot 1.3s infinite; + -webkit-animation-delay: 0.0s; + animation: app-loading-dot 1.3s infinite; + animation-delay: 0.0s; + } + + .app-loading-two { + opacity: 0; + -webkit-animation: dot 1.3s infinite; + -webkit-animation-delay: 0.2s; + animation: app-loading-dot 1.3s infinite; + animation-delay: 0.2s; + } + + .app-loading-three { + opacity: 0; + -webkit-animation: dot 1.3s infinite; + -webkit-animation-delay: 0.3s; + animation: app-loading-dot 1.3s infinite; + animation-delay: 0.3s; + } + + @-webkit-keyframes app-loading-dot { + 0% { + opacity: 0; + } + + 50% { + opacity: 0; + } + + 100% { + opacity: 1; + } + } + + @keyframes app-loading-dot { + 0% { + opacity: 0; + } + + 50% { + opacity: 0; + } + + 100% { + opacity: 1; + } + } +} \ No newline at end of file diff --git a/src/Ombi/Views/Home/Index.cshtml b/src/Ombi/Views/Home/Index.cshtml index e6febc9cc..0517946f9 100644 --- a/src/Ombi/Views/Home/Index.cshtml +++ b/src/Ombi/Views/Home/Index.cshtml @@ -1 +1,11 @@ -Loading.. \ No newline at end of file + +
+ +
+ Loading + . + . + . +
+
+
diff --git a/src/Ombi/webpack.config.vendor.js b/src/Ombi/webpack.config.vendor.js index a77b379d1..15fbe07b4 100644 --- a/src/Ombi/webpack.config.vendor.js +++ b/src/Ombi/webpack.config.vendor.js @@ -48,6 +48,8 @@ module.exports = function (env) { 'font-awesome/scss/font-awesome.scss', 'pace-progress', 'pace-progress/themes/orange/pace-theme-flash.css', + 'ng2-dragula', + 'dragula/dist/dragula.min.css' ] }, output: {