diff --git a/Ombi.Api.Interfaces/IDiscordApi.cs b/Ombi.Api.Interfaces/IDiscordApi.cs new file mode 100644 index 000000000..cb3ff9203 --- /dev/null +++ b/Ombi.Api.Interfaces/IDiscordApi.cs @@ -0,0 +1,38 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2017 Jamie Rees +// File: IDiscordApi.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion + +using System.Threading.Tasks; +using Ombi.Api.Models.Notifications; + +namespace Ombi.Api.Interfaces +{ + public interface IDiscordApi + { + void SendMessage(string message, string webhookId, string webhookToken, string username = null); + Task SendMessageAsync(string message, string webhookId, string webhookToken, string username = null); + } +} \ No newline at end of file diff --git a/Ombi.Api.Interfaces/Ombi.Api.Interfaces.csproj b/Ombi.Api.Interfaces/Ombi.Api.Interfaces.csproj index 201d97b71..05c1aae09 100644 --- a/Ombi.Api.Interfaces/Ombi.Api.Interfaces.csproj +++ b/Ombi.Api.Interfaces/Ombi.Api.Interfaces.csproj @@ -47,6 +47,7 @@ + diff --git a/Ombi.Api.Models/Notifications/DiscordWebhookRequest.cs b/Ombi.Api.Models/Notifications/DiscordWebhookRequest.cs new file mode 100644 index 000000000..653235c08 --- /dev/null +++ b/Ombi.Api.Models/Notifications/DiscordWebhookRequest.cs @@ -0,0 +1,34 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2017 Jamie Rees +// File: DiscordWebhookRequest.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion +namespace Ombi.Api.Models.Notifications +{ + public class DiscordWebhookRequest + { + public string content { get; set; } + public string username { get; set; } + } +} \ No newline at end of file diff --git a/Ombi.Api.Models/Notifications/DiscordWebhookResponse.cs b/Ombi.Api.Models/Notifications/DiscordWebhookResponse.cs new file mode 100644 index 000000000..ac7978c4c --- /dev/null +++ b/Ombi.Api.Models/Notifications/DiscordWebhookResponse.cs @@ -0,0 +1,47 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2017 Jamie Rees +// File: DiscordWebhookResponse.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion + +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; + +namespace Ombi.Api.Models.Notifications +{ + public class DiscordWebhookResponse + { + public string name { get; set; } + [JsonProperty(PropertyName = "channel_id")] + public string channelid { get; set; } + + public string token { get; set; } + public string avatar { get; set; } + [JsonProperty(PropertyName = "guild_id")] + public string guildid { get; set; } + + public string id { get; set; } + + } +} \ No newline at end of file diff --git a/Ombi.Api.Models/Ombi.Api.Models.csproj b/Ombi.Api.Models/Ombi.Api.Models.csproj index 32a55c507..f053da006 100644 --- a/Ombi.Api.Models/Ombi.Api.Models.csproj +++ b/Ombi.Api.Models/Ombi.Api.Models.csproj @@ -62,6 +62,8 @@ + + diff --git a/Ombi.Api/DiscordApi.cs b/Ombi.Api/DiscordApi.cs new file mode 100644 index 000000000..a5214c503 --- /dev/null +++ b/Ombi.Api/DiscordApi.cs @@ -0,0 +1,113 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2017 Jamie Rees +// File: NetflixRouletteApi.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion + +using System; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Ombi.Api.Interfaces; +using Ombi.Api.Models.Netflix; +using Ombi.Api.Models.Notifications; +using RestSharp; + +namespace Ombi.Api +{ + public class DiscordApi : IDiscordApi + { + public DiscordApi(IApiRequest req) + { + Api = req; + } + + private IApiRequest Api { get; } + private Uri Endpoint => new Uri("https://discordapp.com/api/"); //webhooks/270828242636636161/lLysOMhJ96AFO1kvev0bSqP-WCZxKUh1UwfubhIcLkpS0DtM3cg4Pgeraw3waoTXbZii + + + public void SendMessage(string message, string webhookId, string webhookToken, string username = null) + { + var request = new RestRequest + { + Resource = "webhooks/{webhookId}/{webhookToken}" + }; + + request.AddUrlSegment("webhookId", webhookId); + request.AddUrlSegment("webhookToken", webhookToken); + + var body = new DiscordWebhookRequest + { + content = message, + username = username + }; + request.AddJsonBody(body); + + request.AddHeader("Content-Type", "application/json"); + + Api.Execute(request, Endpoint); + } + + public async Task SendMessageAsync(string message, string webhookId, string webhookToken, string username = null) + { + var request = new RestRequest + { + Resource = "webhooks/{webhookId}/{webhookToken}" + }; + + request.AddUrlSegment("webhookId", webhookId); + request.AddUrlSegment("webhookToken", webhookToken); + + var body = new DiscordWebhookRequest + { + content = message, + username = username + }; + request.AddJsonBody(body); + + request.AddHeader("Content-Type", "application/json"); + + await Task.Run( + () => + { + Api.Execute(request, Endpoint); + + }); + } + + + + public NetflixMovieResult CheckNetflix(string title, string year = null) + { + var request = new RestRequest(); + request.AddQueryParameter("title", title); + if (!string.IsNullOrEmpty(year)) + { + request.AddQueryParameter("year", year); + } + var result = Api.Execute(request, Endpoint); + + return JsonConvert.DeserializeObject(result.Content); + } + } +} \ No newline at end of file diff --git a/Ombi.Api/Ombi.Api.csproj b/Ombi.Api/Ombi.Api.csproj index b9151ca5d..0e60de918 100644 --- a/Ombi.Api/Ombi.Api.csproj +++ b/Ombi.Api/Ombi.Api.csproj @@ -69,6 +69,7 @@ + diff --git a/Ombi.Core/ISecurityExtensions.cs b/Ombi.Core/ISecurityExtensions.cs index e3b52a613..0743b5a51 100644 --- a/Ombi.Core/ISecurityExtensions.cs +++ b/Ombi.Core/ISecurityExtensions.cs @@ -29,7 +29,10 @@ namespace Ombi.Core /// Gets the username this could be the alias! We should always use this method when getting the username /// /// The username. - /// null if we cannot find a user + /// The session. + /// + /// null if we cannot find a user + /// string GetUsername(string username, ISession session); } } \ No newline at end of file diff --git a/Ombi.Core/Ombi.Core.csproj b/Ombi.Core/Ombi.Core.csproj index 828ed3b4e..6746f6631 100644 --- a/Ombi.Core/Ombi.Core.csproj +++ b/Ombi.Core/Ombi.Core.csproj @@ -122,6 +122,7 @@ + diff --git a/Ombi.Core/SecurityExtensions.cs b/Ombi.Core/SecurityExtensions.cs index 8ec7f3689..a68884009 100644 --- a/Ombi.Core/SecurityExtensions.cs +++ b/Ombi.Core/SecurityExtensions.cs @@ -94,34 +94,23 @@ namespace Ombi.Core /// Gets the username this could be the alias! We should always use this method when getting the username /// /// The username. - /// null if we cannot find a user + /// + /// + /// null if we cannot find a user + /// public string GetUsername(string username, ISession session) { var plexUser = PlexUsers.GetUserByUsername(username); if (plexUser != null) { - if (!string.IsNullOrEmpty(plexUser.UserAlias)) - { - return plexUser.UserAlias; - } - else - { - return plexUser.Username; - } + return !string.IsNullOrEmpty(plexUser.UserAlias) ? plexUser.UserAlias : plexUser.Username; } var dbUser = UserRepository.GetUserByUsername(username); if (dbUser != null) { var userProps = ByteConverterHelper.ReturnObject(dbUser.UserProperties); - if (!string.IsNullOrEmpty(userProps.UserAlias)) - { - return userProps.UserAlias; - } - else - { - return dbUser.UserName; - } + return !string.IsNullOrEmpty(userProps.UserAlias) ? userProps.UserAlias : dbUser.UserName; } // could be a local user diff --git a/Ombi.Core/SettingModels/DiscordNotificationSettings.cs b/Ombi.Core/SettingModels/DiscordNotificationSettings.cs new file mode 100644 index 000000000..899b7f16e --- /dev/null +++ b/Ombi.Core/SettingModels/DiscordNotificationSettings.cs @@ -0,0 +1,31 @@ +using System; +using Newtonsoft.Json; + +namespace Ombi.Core.SettingModels +{ + public sealed class DiscordNotificationSettings : NotificationSettings + { + 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]; + } + + } +} \ No newline at end of file diff --git a/Ombi.Services/Notification/DiscordNotification.cs b/Ombi.Services/Notification/DiscordNotification.cs new file mode 100644 index 000000000..4cfdfdbb5 --- /dev/null +++ b/Ombi.Services/Notification/DiscordNotification.cs @@ -0,0 +1,165 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: SlackNotification.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion + +using System; +using System.Threading.Tasks; +using NLog; +using Ombi.Api.Interfaces; +using Ombi.Api.Models.Notifications; +using Ombi.Core; +using Ombi.Core.Models; +using Ombi.Core.SettingModels; +using Ombi.Services.Interfaces; + +namespace Ombi.Services.Notification +{ + public class DiscordNotification : INotification + { + public DiscordNotification(IDiscordApi api, ISettingsService sn) + { + Api = api; + Settings = sn; + } + + public string NotificationName => "DiscordNotification"; + + private IDiscordApi Api { get; } + private ISettingsService Settings { get; } + private static Logger Log = LogManager.GetCurrentClassLogger(); + + + public async Task NotifyAsync(NotificationModel model) + { + var settings = Settings.GetSettings(); + + await NotifyAsync(model, settings); + } + + public async Task NotifyAsync(NotificationModel model, Settings settings) + { + if (settings == null) await NotifyAsync(model); + + var pushSettings = (DiscordNotificationSettings)settings; + if (!ValidateConfiguration(pushSettings)) + { + Log.Error("Settings for Slack was not correct, we cannot push a notification"); + return; + } + + switch (model.NotificationType) + { + case NotificationType.NewRequest: + await PushNewRequestAsync(model, pushSettings); + break; + case NotificationType.Issue: + await PushIssueAsync(model, pushSettings); + break; + case NotificationType.RequestAvailable: + break; + case NotificationType.RequestApproved: + break; + case NotificationType.AdminNote: + break; + case NotificationType.Test: + await PushTest(pushSettings); + break; + case NotificationType.RequestDeclined: + await PushRequestDeclinedAsync(model, pushSettings); + break; + case NotificationType.ItemAddedToFaultQueue: + await PushFaultQueue(model, pushSettings); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + private async Task PushNewRequestAsync(NotificationModel model, DiscordNotificationSettings settings) + { + var message = $"{model.Title} has been requested by user: {model.User}"; + await Push(settings, message); + } + + private async Task PushRequestDeclinedAsync(NotificationModel model, DiscordNotificationSettings settings) + { + var message = $"Hello! Your request for {model.Title} has been declined, Sorry!"; + await Push(settings, message); + } + + private async Task PushIssueAsync(NotificationModel model, DiscordNotificationSettings settings) + { + var message = $"A new issue: {model.Body} has been reported by user: {model.User} for the title: {model.Title}"; + await Push(settings, message); + } + + private async Task PushTest(DiscordNotificationSettings settings) + { + var message = $"This is a test from Ombi, if you can see this then we have successfully pushed a notification!"; + await Push(settings, message); + } + + private async Task PushFaultQueue(NotificationModel model, DiscordNotificationSettings settings) + { + var message = $"Hello! The user '{model.User}' has requested {model.Title} but it could not be added. This has been added into the requests queue and will keep retrying"; + await Push(settings, message); + } + + private async Task Push(DiscordNotificationSettings config, string message) + { + try + { + await Api.SendMessageAsync(message, config.WebookId, config.Token, config.Username); + } + catch (Exception e) + { + Log.Error(e); + } + } + + private bool ValidateConfiguration(DiscordNotificationSettings settings) + { + if (!settings.Enabled) + { + return false; + } + if (string.IsNullOrEmpty(settings.WebhookUrl)) + { + return false; + } + try + { + var a = settings.Token; + var b = settings.WebookId; + } + catch (IndexOutOfRangeException) + { + return false; + } + return true; + } + } +} \ No newline at end of file diff --git a/Ombi.Services/Ombi.Services.csproj b/Ombi.Services/Ombi.Services.csproj index fabb8e69f..ec412e87f 100644 --- a/Ombi.Services/Ombi.Services.csproj +++ b/Ombi.Services/Ombi.Services.csproj @@ -126,6 +126,7 @@ + diff --git a/Ombi.UI/Modules/Admin/AdminModule.cs b/Ombi.UI/Modules/Admin/AdminModule.cs index ea320ff14..c0d79d183 100644 --- a/Ombi.UI/Modules/Admin/AdminModule.cs +++ b/Ombi.UI/Modules/Admin/AdminModule.cs @@ -93,6 +93,8 @@ namespace Ombi.UI.Modules.Admin private IAnalytics Analytics { get; } private IRecentlyAdded RecentlyAdded { get; } private ISettingsService NotifySettings { get; } + private ISettingsService DiscordSettings { get; } + private IDiscordApi DiscordApi { get; } private static Logger Log = LogManager.GetCurrentClassLogger(); public AdminModule(ISettingsService prService, @@ -118,7 +120,9 @@ namespace Ombi.UI.Modules.Admin ISlackApi slackApi, ISettingsService lp, ISettingsService scheduler, IJobRecord rec, IAnalytics analytics, ISettingsService notifyService, IRecentlyAdded recentlyAdded, - ISettingsService watcherSettings + ISettingsService watcherSettings , + ISettingsService discord, + IDiscordApi discordapi , ISecurityExtensions security) : base("admin", prService, security) { PrService = prService; @@ -150,6 +154,8 @@ namespace Ombi.UI.Modules.Admin NotifySettings = notifyService; RecentlyAdded = recentlyAdded; WatcherSettings = watcherSettings; + DiscordSettings = discord; + DiscordApi = discordapi; Before += (ctx) => Security.AdminLoginRedirect(Permissions.Administrator, ctx); @@ -208,10 +214,13 @@ namespace Ombi.UI.Modules.Admin Post["/testslacknotification", true] = async (x, ct) => await TestSlackNotification(); - Get["/slacknotification"] = _ => SlackNotifications(); Post["/slacknotification"] = _ => SaveSlackNotifications(); + Post["/testdiscordnotification", true] = async (x, ct) => await TestDiscordNotification(); + Get["/discordnotification", true] = async (x, ct) => await DiscordNotification(); + Post["/discordnotification", true] = async (x, ct) => await SaveDiscordNotifications(); + Get["/landingpage", true] = async (x, ct) => await LandingPage(); Post["/landingpage", true] = async (x, ct) => await SaveLandingPage(); @@ -918,6 +927,71 @@ namespace Ombi.UI.Modules.Admin : new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." }); } + private async Task DiscordNotification() + { + var settings = await DiscordSettings.GetSettingsAsync(); + return View["DiscordNotification", settings]; + } + + private async Task TestDiscordNotification() + { + var settings = this.BindAndValidate(); + if (!ModelValidationResult.IsValid) + { + return Response.AsJson(ModelValidationResult.SendJsonError()); + } + var notificationModel = new NotificationModel + { + NotificationType = NotificationType.Test, + DateTime = DateTime.Now + }; + + var currentDicordSettings = await DiscordSettings.GetSettingsAsync(); + try + { + NotificationService.Subscribe(new DiscordNotification(DiscordApi, DiscordSettings)); + settings.Enabled = true; + await NotificationService.Publish(notificationModel, settings); + Log.Info("Sent Discord notification test"); + } + catch (Exception e) + { + Log.Error(e, "Failed to subscribe and publish test Discord Notification"); + } + finally + { + if (!currentDicordSettings.Enabled) + { + NotificationService.UnSubscribe(new DiscordNotification(DiscordApi, DiscordSettings)); + } + } + return Response.AsJson(new JsonResponseModel { Result = true, Message = "Successfully sent a test Discord Notification! If you do not receive it please check the logs." }); + } + + private async Task SaveDiscordNotifications() + { + var settings = this.BindAndValidate(); + if (!ModelValidationResult.IsValid) + { + return Response.AsJson(ModelValidationResult.SendJsonError()); + } + + var result = await DiscordSettings.SaveSettingsAsync(settings); + if (settings.Enabled) + { + NotificationService.Subscribe(new DiscordNotification(DiscordApi, DiscordSettings)); + } + else + { + NotificationService.UnSubscribe(new DiscordNotification(DiscordApi, DiscordSettings)); + } + + Log.Info("Saved discord settings, result: {0}", result); + return Response.AsJson(result + ? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for Discord Notifications!" } + : new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." }); + } + private async Task LandingPage() { var settings = await LandingSettings.GetSettingsAsync(); diff --git a/Ombi.UI/Modules/BaseModule.cs b/Ombi.UI/Modules/BaseModule.cs index 59904dcb6..989e3ee1a 100644 --- a/Ombi.UI/Modules/BaseModule.cs +++ b/Ombi.UI/Modules/BaseModule.cs @@ -115,7 +115,7 @@ namespace Ombi.UI.Modules var username = Security.GetUsername(User.UserName, Session); if (string.IsNullOrEmpty(username)) { - return Session[SessionKeys.UsernameKey].ToString(); + return "Unknown User"; } _username = username; } diff --git a/Ombi.UI/Ombi.UI.csproj b/Ombi.UI/Ombi.UI.csproj index d984e4562..30083f4d5 100644 --- a/Ombi.UI/Ombi.UI.csproj +++ b/Ombi.UI/Ombi.UI.csproj @@ -789,6 +789,9 @@ Always + + Always + web.config diff --git a/Ombi.UI/Views/Admin/DiscordNotification.cshtml b/Ombi.UI/Views/Admin/DiscordNotification.cshtml new file mode 100644 index 000000000..008b96e01 --- /dev/null +++ b/Ombi.UI/Views/Admin/DiscordNotification.cshtml @@ -0,0 +1,99 @@ +@using Ombi.UI.Helpers +@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase +@Html.Partial("Shared/Partial/_Sidebar") + +
+
+
+ Discord Notifications + + @Html.Checkbox(Model.Enabled, "Enabled", "Enabled") + +
+ + This is the full webhook url. + Discord > Edit Channel > Webhooks > Create Webook > Copy the Webhook Url > Press Save +
+ +
+
+ +
+ + You can override the default username +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + \ No newline at end of file diff --git a/Ombi.UI/Views/Shared/Partial/_Sidebar.cshtml b/Ombi.UI/Views/Shared/Partial/_Sidebar.cshtml index df5969a95..d38827cf8 100644 --- a/Ombi.UI/Views/Shared/Partial/_Sidebar.cshtml +++ b/Ombi.UI/Views/Shared/Partial/_Sidebar.cshtml @@ -19,6 +19,7 @@ @Html.GetSidebarUrl(Context, "/admin/pushbulletnotification", "Pushbullet Notifications") @Html.GetSidebarUrl(Context, "/admin/pushovernotification", "Pushover Notifications") @Html.GetSidebarUrl(Context, "/admin/slacknotification", "Slack Notifications") + @Html.GetSidebarUrl(Context, "/admin/discordnotification", "Discord Notifications") @Html.GetSidebarUrl(Context, "/admin/logs", "Logs") @Html.GetSidebarUrl(Context, "/admin/status", "Status") @Html.GetSidebarUrl(Context, "/admin/scheduledjobs", "Scheduled Jobs")