diff --git a/src/NzbDrone.Core.Test/NotificationTests/NotificationBaseFixture.cs b/src/NzbDrone.Core.Test/NotificationTests/NotificationBaseFixture.cs index 42c92c909..1e52d6275 100644 --- a/src/NzbDrone.Core.Test/NotificationTests/NotificationBaseFixture.cs +++ b/src/NzbDrone.Core.Test/NotificationTests/NotificationBaseFixture.cs @@ -3,7 +3,6 @@ using FluentAssertions; using FluentValidation.Results; using NUnit.Framework; using NzbDrone.Core.Notifications; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; using NzbDrone.Test.Common; @@ -12,9 +11,9 @@ namespace NzbDrone.Core.Test.NotificationTests [TestFixture] public class NotificationBaseFixture : TestBase { - private class TestSetting : IProviderConfig + private class TestSetting : NotificationBaseSettings { - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(); } diff --git a/src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs b/src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs index 309da6b26..c411c3bea 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/BinSearch.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; using AngleSharp.Html.Parser; +using Equ; using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; @@ -210,7 +211,7 @@ namespace NzbDrone.Core.Indexers.Definitions public Action, DateTime?> CookiesUpdater { get; set; } } - public class BinSearchSettings : IIndexerSettings + public class BinSearchSettings : MemberwiseEquatable, IIndexerSettings { [FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")] public string BaseUrl { get; set; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Headphones/HeadphonesSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/Headphones/HeadphonesSettings.cs index ff1770cdb..c75a740a7 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Headphones/HeadphonesSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Headphones/HeadphonesSettings.cs @@ -1,3 +1,4 @@ +using Equ; using FluentValidation; using NzbDrone.Core.Annotations; using NzbDrone.Core.Validation; @@ -14,7 +15,7 @@ namespace NzbDrone.Core.Indexers.Headphones } } - public class HeadphonesSettings : IIndexerSettings + public class HeadphonesSettings : MemberwiseEquatable, IIndexerSettings { private static readonly HeadphonesSettingsValidator Validator = new (); diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabSettings.cs index 67b787e12..e9dce3ae0 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabSettings.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Text.RegularExpressions; +using Equ; using FluentValidation; using NzbDrone.Common.Extensions; using NzbDrone.Core.Annotations; @@ -46,7 +47,7 @@ namespace NzbDrone.Core.Indexers.Newznab } } - public class NewznabSettings : IIndexerSettings + public class NewznabSettings : MemberwiseEquatable, IIndexerSettings { private static readonly NewznabSettingsValidator Validator = new (); @@ -75,6 +76,7 @@ namespace NzbDrone.Core.Indexers.Newznab [FieldDefinition(7)] public IndexerBaseSettings BaseSettings { get; set; } = new (); + [MemberwiseEqualityIgnore] public NewznabCapabilitiesSettings Capabilities { get; set; } // Field 8 is used by TorznabSettings MinimumSeeders diff --git a/src/NzbDrone.Core/Indexers/Definitions/NzbIndex.cs b/src/NzbDrone.Core/Indexers/Definitions/NzbIndex.cs index 8fe5f4d04..ba5b24616 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/NzbIndex.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/NzbIndex.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Text.RegularExpressions; +using Equ; using FluentValidation; using Newtonsoft.Json.Linq; using NLog; @@ -1178,7 +1179,7 @@ namespace NzbDrone.Core.Indexers.Definitions } } - public class NzbIndexSettings : IIndexerSettings + public class NzbIndexSettings : MemberwiseEquatable, IIndexerSettings { private static readonly NzbIndexSettingsValidator Validator = new (); diff --git a/src/NzbDrone.Core/Indexers/IndexerBaseSettings.cs b/src/NzbDrone.Core/Indexers/IndexerBaseSettings.cs index 5bada9b42..0bd6cc53b 100644 --- a/src/NzbDrone.Core/Indexers/IndexerBaseSettings.cs +++ b/src/NzbDrone.Core/Indexers/IndexerBaseSettings.cs @@ -1,3 +1,4 @@ +using Equ; using FluentValidation; using NzbDrone.Core.Annotations; @@ -19,7 +20,7 @@ namespace NzbDrone.Core.Indexers } } - public class IndexerBaseSettings + public class IndexerBaseSettings : MemberwiseEquatable { [FieldDefinition(1, Type = FieldType.Number, Label = "IndexerSettingsQueryLimit", HelpText = "IndexerSettingsQueryLimitHelpText", Advanced = true)] public int? QueryLimit { get; set; } diff --git a/src/NzbDrone.Core/Indexers/IndexerDefinition.cs b/src/NzbDrone.Core/Indexers/IndexerDefinition.cs index 4b8a5f649..5a3accf0b 100644 --- a/src/NzbDrone.Core/Indexers/IndexerDefinition.cs +++ b/src/NzbDrone.Core/Indexers/IndexerDefinition.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using Equ; using NzbDrone.Core.Datastore; using NzbDrone.Core.Indexers.Definitions.Cardigann; using NzbDrone.Core.Profiles; @@ -10,23 +11,47 @@ namespace NzbDrone.Core.Indexers { public class IndexerDefinition : ProviderDefinition { - public string[] IndexerUrls { get; set; } - public string[] LegacyUrls { get; set; } + [MemberwiseEqualityIgnore] + public IEnumerable IndexerUrls { get; set; } + + [MemberwiseEqualityIgnore] + public IEnumerable LegacyUrls { get; set; } + public string Description { get; set; } public Encoding Encoding { get; set; } public string Language { get; set; } + + [MemberwiseEqualityIgnore] public DownloadProtocol Protocol { get; set; } + + [MemberwiseEqualityIgnore] public IndexerPrivacy Privacy { get; set; } + + [MemberwiseEqualityIgnore] public bool SupportsRss { get; set; } + + [MemberwiseEqualityIgnore] public bool SupportsSearch { get; set; } + + [MemberwiseEqualityIgnore] public bool SupportsRedirect { get; set; } + + [MemberwiseEqualityIgnore] public bool SupportsPagination { get; set; } + + [MemberwiseEqualityIgnore] public IndexerCapabilities Capabilities { get; set; } + public int Priority { get; set; } = 25; public bool Redirect { get; set; } public int DownloadClientId { get; set; } + + [MemberwiseEqualityIgnore] public DateTime Added { get; set; } + public int AppProfileId { get; set; } + + [MemberwiseEqualityIgnore] public LazyLoaded AppProfile { get; set; } public List ExtraFields { get; set; } = new (); diff --git a/src/NzbDrone.Core/Indexers/IndexerTorrentBaseSettings.cs b/src/NzbDrone.Core/Indexers/IndexerTorrentBaseSettings.cs index fd5d4c813..1b7b8ff18 100644 --- a/src/NzbDrone.Core/Indexers/IndexerTorrentBaseSettings.cs +++ b/src/NzbDrone.Core/Indexers/IndexerTorrentBaseSettings.cs @@ -1,3 +1,4 @@ +using Equ; using FluentValidation; using NzbDrone.Core.Annotations; using NzbDrone.Core.Validation; @@ -50,7 +51,7 @@ namespace NzbDrone.Core.Indexers } } - public class IndexerTorrentBaseSettings + public class IndexerTorrentBaseSettings : MemberwiseEquatable { [FieldDefinition(1, Type = FieldType.Number, Label = "IndexerSettingsAppsMinimumSeeders", HelpText = "IndexerSettingsAppsMinimumSeedersHelpText", Advanced = true)] public int? AppMinimumSeeders { get; set; } diff --git a/src/NzbDrone.Core/Indexers/Settings/NoAuthTorrentBaseSettings.cs b/src/NzbDrone.Core/Indexers/Settings/NoAuthTorrentBaseSettings.cs index 42f800dc8..2c95b1202 100644 --- a/src/NzbDrone.Core/Indexers/Settings/NoAuthTorrentBaseSettings.cs +++ b/src/NzbDrone.Core/Indexers/Settings/NoAuthTorrentBaseSettings.cs @@ -1,3 +1,4 @@ +using Equ; using FluentValidation; using NzbDrone.Core.Annotations; using NzbDrone.Core.Validation; @@ -14,7 +15,7 @@ namespace NzbDrone.Core.Indexers.Settings } } - public class NoAuthTorrentBaseSettings : ITorrentIndexerSettings + public class NoAuthTorrentBaseSettings : MemberwiseEquatable, ITorrentIndexerSettings { private static readonly NoAuthSettingsValidator Validator = new (); diff --git a/src/NzbDrone.Core/Notifications/Apprise/AppriseSettings.cs b/src/NzbDrone.Core/Notifications/Apprise/AppriseSettings.cs index 31c709253..56f39f15c 100644 --- a/src/NzbDrone.Core/Notifications/Apprise/AppriseSettings.cs +++ b/src/NzbDrone.Core/Notifications/Apprise/AppriseSettings.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using FluentValidation; using NzbDrone.Common.Extensions; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.Apprise @@ -35,7 +34,7 @@ namespace NzbDrone.Core.Notifications.Apprise } } - public class AppriseSettings : IProviderConfig + public class AppriseSettings : NotificationBaseSettings { private static readonly AppriseSettingsValidator Validator = new (); @@ -66,7 +65,7 @@ namespace NzbDrone.Core.Notifications.Apprise [FieldDefinition(7, Label = "Password", Type = FieldType.Password, HelpText = "HTTP Basic Auth Password", Privacy = PrivacyLevel.Password)] public string AuthPassword { get; set; } - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Notifications/CustomScript/CustomScriptSettings.cs b/src/NzbDrone.Core/Notifications/CustomScript/CustomScriptSettings.cs index ce5a398ed..f98b3acf8 100644 --- a/src/NzbDrone.Core/Notifications/CustomScript/CustomScriptSettings.cs +++ b/src/NzbDrone.Core/Notifications/CustomScript/CustomScriptSettings.cs @@ -1,6 +1,5 @@ using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; using NzbDrone.Core.Validation.Paths; @@ -16,7 +15,7 @@ namespace NzbDrone.Core.Notifications.CustomScript } } - public class CustomScriptSettings : IProviderConfig + public class CustomScriptSettings : NotificationBaseSettings { private static readonly CustomScriptSettingsValidator Validator = new CustomScriptSettingsValidator(); @@ -26,7 +25,7 @@ namespace NzbDrone.Core.Notifications.CustomScript [FieldDefinition(1, Label = "Arguments", HelpText = "Arguments to pass to the script", Hidden = HiddenType.HiddenIfNotSet)] public string Arguments { get; set; } - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Notifications/Discord/DiscordSettings.cs b/src/NzbDrone.Core/Notifications/Discord/DiscordSettings.cs index c571b4fb5..f2619457f 100644 --- a/src/NzbDrone.Core/Notifications/Discord/DiscordSettings.cs +++ b/src/NzbDrone.Core/Notifications/Discord/DiscordSettings.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.Discord @@ -14,7 +13,7 @@ namespace NzbDrone.Core.Notifications.Discord } } - public class DiscordSettings : IProviderConfig + public class DiscordSettings : NotificationBaseSettings { public DiscordSettings() { @@ -47,7 +46,7 @@ namespace NzbDrone.Core.Notifications.Discord [FieldDefinition(4, Label = "On Grab Fields", Advanced = true, SelectOptions = typeof(DiscordGrabFieldType), HelpText = "Change the fields that are passed in for this 'on grab' notification", Type = FieldType.Select)] public IEnumerable GrabFields { get; set; } - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Notifications/Email/EmailSettings.cs b/src/NzbDrone.Core/Notifications/Email/EmailSettings.cs index 2ef1d9d0c..0ef16b3a8 100644 --- a/src/NzbDrone.Core/Notifications/Email/EmailSettings.cs +++ b/src/NzbDrone.Core/Notifications/Email/EmailSettings.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.Email @@ -26,7 +25,7 @@ namespace NzbDrone.Core.Notifications.Email } } - public class EmailSettings : IProviderConfig + public class EmailSettings : NotificationBaseSettings { private static readonly EmailSettingsValidator Validator = new EmailSettingsValidator(); @@ -65,7 +64,7 @@ namespace NzbDrone.Core.Notifications.Email [FieldDefinition(8, Label = "BCC Address(es)", HelpText = "Comma separated list of email bcc recipients", Placeholder = "example@email.com,example1@email.com", Advanced = true)] public IEnumerable Bcc { get; set; } - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Notifications/Gotify/GotifySettings.cs b/src/NzbDrone.Core/Notifications/Gotify/GotifySettings.cs index 7c5021e58..e4267a911 100644 --- a/src/NzbDrone.Core/Notifications/Gotify/GotifySettings.cs +++ b/src/NzbDrone.Core/Notifications/Gotify/GotifySettings.cs @@ -1,6 +1,5 @@ using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.Gotify @@ -14,7 +13,7 @@ namespace NzbDrone.Core.Notifications.Gotify } } - public class GotifySettings : IProviderConfig + public class GotifySettings : NotificationBaseSettings { private static readonly GotifySettingsValidator Validator = new GotifySettingsValidator(); @@ -32,7 +31,7 @@ namespace NzbDrone.Core.Notifications.Gotify [FieldDefinition(2, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(GotifyPriority), HelpText = "Priority of the notification")] public int Priority { get; set; } - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Notifications/Join/JoinSettings.cs b/src/NzbDrone.Core/Notifications/Join/JoinSettings.cs index 301f1f87f..3c012ccc5 100644 --- a/src/NzbDrone.Core/Notifications/Join/JoinSettings.cs +++ b/src/NzbDrone.Core/Notifications/Join/JoinSettings.cs @@ -1,6 +1,5 @@ using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.Join @@ -14,7 +13,7 @@ namespace NzbDrone.Core.Notifications.Join } } - public class JoinSettings : IProviderConfig + public class JoinSettings : NotificationBaseSettings { public JoinSettings() { @@ -35,7 +34,7 @@ namespace NzbDrone.Core.Notifications.Join [FieldDefinition(3, Label = "Notification Priority", Type = FieldType.Select, SelectOptions = typeof(JoinPriority))] public int Priority { get; set; } - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Notifications/Mailgun/MailgunSettings.cs b/src/NzbDrone.Core/Notifications/Mailgun/MailgunSettings.cs index 896239ef5..cd3b15609 100644 --- a/src/NzbDrone.Core/Notifications/Mailgun/MailgunSettings.cs +++ b/src/NzbDrone.Core/Notifications/Mailgun/MailgunSettings.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.Mailgun @@ -17,7 +16,7 @@ namespace NzbDrone.Core.Notifications.Mailgun } } - public class MailgunSettings : IProviderConfig + public class MailgunSettings : NotificationBaseSettings { private static readonly MailGunSettingsValidator Validator = new MailGunSettingsValidator(); @@ -41,7 +40,7 @@ namespace NzbDrone.Core.Notifications.Mailgun [FieldDefinition(4, Label = "Recipient Address(es)", Type = FieldType.Tag, Placeholder = "example@email.com,example1@email.com")] public IEnumerable Recipients { get; set; } - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Notifications/Notifiarr/NotifiarrSettings.cs b/src/NzbDrone.Core/Notifications/Notifiarr/NotifiarrSettings.cs index 1a8bb06c9..24fa91168 100644 --- a/src/NzbDrone.Core/Notifications/Notifiarr/NotifiarrSettings.cs +++ b/src/NzbDrone.Core/Notifications/Notifiarr/NotifiarrSettings.cs @@ -1,6 +1,5 @@ using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.Notifiarr @@ -13,14 +12,14 @@ namespace NzbDrone.Core.Notifications.Notifiarr } } - public class NotifiarrSettings : IProviderConfig + public class NotifiarrSettings : NotificationBaseSettings { private static readonly NotifiarrSettingsValidator Validator = new NotifiarrSettingsValidator(); [FieldDefinition(0, Label = "API Key", Privacy = PrivacyLevel.ApiKey, HelpText = "Your API key from your profile", HelpLink = "https://notifiarr.com")] public string APIKey { get; set; } - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Notifications/NotificationBase.cs b/src/NzbDrone.Core/Notifications/NotificationBase.cs index 61af1d21e..f8c7adb69 100644 --- a/src/NzbDrone.Core/Notifications/NotificationBase.cs +++ b/src/NzbDrone.Core/Notifications/NotificationBase.cs @@ -6,7 +6,7 @@ using NzbDrone.Core.ThingiProvider; namespace NzbDrone.Core.Notifications { public abstract class NotificationBase : INotification - where TSettings : IProviderConfig, new() + where TSettings : NotificationBaseSettings, new() { protected const string RELEASE_GRABBED_TITLE = "Release Grabbed"; protected const string HEALTH_ISSUE_TITLE = "Health Check Failure"; diff --git a/src/NzbDrone.Core/Notifications/NotificationBaseSettings.cs b/src/NzbDrone.Core/Notifications/NotificationBaseSettings.cs new file mode 100644 index 000000000..26e9117ab --- /dev/null +++ b/src/NzbDrone.Core/Notifications/NotificationBaseSettings.cs @@ -0,0 +1,11 @@ +using Equ; +using NzbDrone.Core.ThingiProvider; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Notifications +{ + public abstract class NotificationBaseSettings : MemberwiseEquatable, IProviderConfig + { + public abstract NzbDroneValidationResult Validate(); + } +} diff --git a/src/NzbDrone.Core/Notifications/Ntfy/NtfySettings.cs b/src/NzbDrone.Core/Notifications/Ntfy/NtfySettings.cs index 1c1cedec3..5637fb779 100644 --- a/src/NzbDrone.Core/Notifications/Ntfy/NtfySettings.cs +++ b/src/NzbDrone.Core/Notifications/Ntfy/NtfySettings.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using FluentValidation; using NzbDrone.Common.Extensions; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.Ntfy @@ -24,7 +23,7 @@ namespace NzbDrone.Core.Notifications.Ntfy private static List InvalidTopics => new List { "announcements", "app", "docs", "settings", "stats", "mytopic-rw", "mytopic-ro", "mytopic-wo" }; } - public class NtfySettings : IProviderConfig + public class NtfySettings : NotificationBaseSettings { private static readonly NtfySettingsValidator Validator = new NtfySettingsValidator(); @@ -58,7 +57,7 @@ namespace NzbDrone.Core.Notifications.Ntfy [FieldDefinition(7, Label = "Click URL", Type = FieldType.Url, HelpText = "Optional link when user clicks notification")] public string ClickUrl { get; set; } - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Notifications/Prowl/ProwlSettings.cs b/src/NzbDrone.Core/Notifications/Prowl/ProwlSettings.cs index 21c5ec7b9..dc4b95d8a 100644 --- a/src/NzbDrone.Core/Notifications/Prowl/ProwlSettings.cs +++ b/src/NzbDrone.Core/Notifications/Prowl/ProwlSettings.cs @@ -1,6 +1,5 @@ using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.Prowl @@ -13,7 +12,7 @@ namespace NzbDrone.Core.Notifications.Prowl } } - public class ProwlSettings : IProviderConfig + public class ProwlSettings : NotificationBaseSettings { private static readonly ProwlSettingsValidator Validator = new ProwlSettingsValidator(); @@ -25,7 +24,7 @@ namespace NzbDrone.Core.Notifications.Prowl public bool IsValid => !string.IsNullOrWhiteSpace(ApiKey) && Priority >= -2 && Priority <= 2; - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Notifications/PushBullet/PushBulletSettings.cs b/src/NzbDrone.Core/Notifications/PushBullet/PushBulletSettings.cs index 93ec03a38..b7b6aea21 100644 --- a/src/NzbDrone.Core/Notifications/PushBullet/PushBulletSettings.cs +++ b/src/NzbDrone.Core/Notifications/PushBullet/PushBulletSettings.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.PushBullet @@ -15,7 +14,7 @@ namespace NzbDrone.Core.Notifications.PushBullet } } - public class PushBulletSettings : IProviderConfig + public class PushBulletSettings : NotificationBaseSettings { private static readonly PushBulletSettingsValidator Validator = new PushBulletSettingsValidator(); @@ -37,7 +36,7 @@ namespace NzbDrone.Core.Notifications.PushBullet [FieldDefinition(3, Label = "Sender ID", HelpText = "The device ID to send notifications from, use device_iden in the device's URL on pushbullet.com (leave blank to send from yourself)")] public string SenderId { get; set; } - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Notifications/Pushcut/PushcutSettings.cs b/src/NzbDrone.Core/Notifications/Pushcut/PushcutSettings.cs index 625bca01e..5e4a0852d 100644 --- a/src/NzbDrone.Core/Notifications/Pushcut/PushcutSettings.cs +++ b/src/NzbDrone.Core/Notifications/Pushcut/PushcutSettings.cs @@ -1,6 +1,5 @@ using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.Pushcut @@ -14,7 +13,7 @@ namespace NzbDrone.Core.Notifications.Pushcut } } - public class PushcutSettings : IProviderConfig + public class PushcutSettings : NotificationBaseSettings { private static readonly PushcutSettingsValidator Validator = new (); @@ -27,7 +26,7 @@ namespace NzbDrone.Core.Notifications.Pushcut [FieldDefinition(2, Label = "Time sensitive", Type = FieldType.Checkbox, HelpText = "Check to mark the notification as \"Time-Sensitive\"")] public bool TimeSensitive { get; set; } - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Notifications/Pushover/PushoverSettings.cs b/src/NzbDrone.Core/Notifications/Pushover/PushoverSettings.cs index 3d573be78..f9d465c69 100644 --- a/src/NzbDrone.Core/Notifications/Pushover/PushoverSettings.cs +++ b/src/NzbDrone.Core/Notifications/Pushover/PushoverSettings.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.Pushover @@ -17,7 +16,7 @@ namespace NzbDrone.Core.Notifications.Pushover } } - public class PushoverSettings : IProviderConfig + public class PushoverSettings : NotificationBaseSettings { private static readonly PushoverSettingsValidator Validator = new PushoverSettingsValidator(); @@ -51,7 +50,7 @@ namespace NzbDrone.Core.Notifications.Pushover public bool IsValid => !string.IsNullOrWhiteSpace(UserKey) && Priority >= -1 && Priority <= 2; - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Notifications/SendGrid/SendGridSettings.cs b/src/NzbDrone.Core/Notifications/SendGrid/SendGridSettings.cs index fa9ef39ae..0eb3d6abc 100644 --- a/src/NzbDrone.Core/Notifications/SendGrid/SendGridSettings.cs +++ b/src/NzbDrone.Core/Notifications/SendGrid/SendGridSettings.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.SendGrid @@ -18,7 +17,7 @@ namespace NzbDrone.Core.Notifications.SendGrid } } - public class SendGridSettings : IProviderConfig + public class SendGridSettings : NotificationBaseSettings { private static readonly SendGridSettingsValidator Validator = new SendGridSettingsValidator(); @@ -39,7 +38,7 @@ namespace NzbDrone.Core.Notifications.SendGrid [FieldDefinition(3, Label = "Recipient Address(es)", Type = FieldType.Tag, Placeholder = "example@email.com,example1@email.com")] public IEnumerable Recipients { get; set; } - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Notifications/Signal/SignalSettings.cs b/src/NzbDrone.Core/Notifications/Signal/SignalSettings.cs index 8906a45e3..b9685c973 100644 --- a/src/NzbDrone.Core/Notifications/Signal/SignalSettings.cs +++ b/src/NzbDrone.Core/Notifications/Signal/SignalSettings.cs @@ -1,6 +1,5 @@ using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.Signal @@ -16,7 +15,7 @@ namespace NzbDrone.Core.Notifications.Signal } } - public class SignalSettings : IProviderConfig + public class SignalSettings : NotificationBaseSettings { private static readonly SignalSettingsValidator Validator = new (); @@ -41,7 +40,7 @@ namespace NzbDrone.Core.Notifications.Signal [FieldDefinition(6, Label = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password, HelpText = "Password used to authenticate requests toward signal-api")] public string AuthPassword { get; set; } - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Notifications/Simplepush/SimplepushSettings.cs b/src/NzbDrone.Core/Notifications/Simplepush/SimplepushSettings.cs index af8b211ef..704447b34 100644 --- a/src/NzbDrone.Core/Notifications/Simplepush/SimplepushSettings.cs +++ b/src/NzbDrone.Core/Notifications/Simplepush/SimplepushSettings.cs @@ -1,6 +1,5 @@ using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.Simplepush @@ -13,7 +12,7 @@ namespace NzbDrone.Core.Notifications.Simplepush } } - public class SimplepushSettings : IProviderConfig + public class SimplepushSettings : NotificationBaseSettings { private static readonly SimplepushSettingsValidator Validator = new SimplepushSettingsValidator(); @@ -25,7 +24,7 @@ namespace NzbDrone.Core.Notifications.Simplepush public bool IsValid => !string.IsNullOrWhiteSpace(Key); - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Notifications/Slack/SlackSettings.cs b/src/NzbDrone.Core/Notifications/Slack/SlackSettings.cs index 399a1ae46..8969ecae0 100644 --- a/src/NzbDrone.Core/Notifications/Slack/SlackSettings.cs +++ b/src/NzbDrone.Core/Notifications/Slack/SlackSettings.cs @@ -1,6 +1,5 @@ using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.Slack @@ -14,7 +13,7 @@ namespace NzbDrone.Core.Notifications.Slack } } - public class SlackSettings : IProviderConfig + public class SlackSettings : NotificationBaseSettings { private static readonly SlackSettingsValidator Validator = new SlackSettingsValidator(); @@ -30,7 +29,7 @@ namespace NzbDrone.Core.Notifications.Slack [FieldDefinition(3, Label = "Channel", HelpText = "Overrides the default channel for the incoming webhook (#other-channel)", Type = FieldType.Textbox)] public string Channel { get; set; } - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Notifications/Telegram/TelegramSettings.cs b/src/NzbDrone.Core/Notifications/Telegram/TelegramSettings.cs index 4ff40ae93..49a37b38e 100644 --- a/src/NzbDrone.Core/Notifications/Telegram/TelegramSettings.cs +++ b/src/NzbDrone.Core/Notifications/Telegram/TelegramSettings.cs @@ -1,6 +1,5 @@ using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.Telegram @@ -16,7 +15,7 @@ namespace NzbDrone.Core.Notifications.Telegram } } - public class TelegramSettings : IProviderConfig + public class TelegramSettings : NotificationBaseSettings { private static readonly TelegramSettingsValidator Validator = new TelegramSettingsValidator(); @@ -35,7 +34,7 @@ namespace NzbDrone.Core.Notifications.Telegram [FieldDefinition(4, Label = "NotificationsTelegramSettingsIncludeAppName", Type = FieldType.Checkbox, HelpText = "NotificationsTelegramSettingsIncludeAppNameHelpText")] public bool IncludeAppNameInTitle { get; set; } - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Notifications/Twitter/TwitterSettings.cs b/src/NzbDrone.Core/Notifications/Twitter/TwitterSettings.cs index b0702b010..017ba519e 100644 --- a/src/NzbDrone.Core/Notifications/Twitter/TwitterSettings.cs +++ b/src/NzbDrone.Core/Notifications/Twitter/TwitterSettings.cs @@ -1,7 +1,6 @@ using FluentValidation; using NzbDrone.Common.Extensions; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.Twitter @@ -28,7 +27,7 @@ namespace NzbDrone.Core.Notifications.Twitter } } - public class TwitterSettings : IProviderConfig + public class TwitterSettings : NotificationBaseSettings { private static readonly TwitterSettingsValidator Validator = new TwitterSettingsValidator(); @@ -59,7 +58,7 @@ namespace NzbDrone.Core.Notifications.Twitter [FieldDefinition(6, Label = "Connect to Twitter", Type = FieldType.OAuth)] public string AuthorizeNotification { get; set; } - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Notifications/Webhook/WebhookBase.cs b/src/NzbDrone.Core/Notifications/Webhook/WebhookBase.cs index fabb59e3b..a582b0ef4 100644 --- a/src/NzbDrone.Core/Notifications/Webhook/WebhookBase.cs +++ b/src/NzbDrone.Core/Notifications/Webhook/WebhookBase.cs @@ -1,10 +1,9 @@ using NzbDrone.Core.Configuration; -using NzbDrone.Core.ThingiProvider; namespace NzbDrone.Core.Notifications.Webhook { public abstract class WebhookBase : NotificationBase - where TSettings : IProviderConfig, new() + where TSettings : NotificationBaseSettings, new() { private readonly IConfigFileProvider _configFileProvider; private readonly IConfigService _configService; diff --git a/src/NzbDrone.Core/Notifications/Webhook/WebhookSettings.cs b/src/NzbDrone.Core/Notifications/Webhook/WebhookSettings.cs index d635173cc..24c5a846e 100644 --- a/src/NzbDrone.Core/Notifications/Webhook/WebhookSettings.cs +++ b/src/NzbDrone.Core/Notifications/Webhook/WebhookSettings.cs @@ -1,7 +1,6 @@ using System; using FluentValidation; using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; namespace NzbDrone.Core.Notifications.Webhook @@ -14,7 +13,7 @@ namespace NzbDrone.Core.Notifications.Webhook } } - public class WebhookSettings : IProviderConfig + public class WebhookSettings : NotificationBaseSettings { private static readonly WebhookSettingsValidator Validator = new WebhookSettingsValidator(); @@ -35,7 +34,7 @@ namespace NzbDrone.Core.Notifications.Webhook [FieldDefinition(3, Label = "Password", HelpText = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)] public string Password { get; set; } - public NzbDroneValidationResult Validate() + public override NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); } diff --git a/src/NzbDrone.Core/Prowlarr.Core.csproj b/src/NzbDrone.Core/Prowlarr.Core.csproj index 29ef56865..8c40a39ff 100644 --- a/src/NzbDrone.Core/Prowlarr.Core.csproj +++ b/src/NzbDrone.Core/Prowlarr.Core.csproj @@ -5,6 +5,7 @@ + diff --git a/src/NzbDrone.Core/ThingiProvider/ProviderDefinition.cs b/src/NzbDrone.Core/ThingiProvider/ProviderDefinition.cs index 292bc4bc5..238317be1 100644 --- a/src/NzbDrone.Core/ThingiProvider/ProviderDefinition.cs +++ b/src/NzbDrone.Core/ThingiProvider/ProviderDefinition.cs @@ -1,11 +1,15 @@ +using System; using System.Collections.Generic; using System.Text.Json.Serialization; +using Equ; using NzbDrone.Core.Datastore; namespace NzbDrone.Core.ThingiProvider { - public abstract class ProviderDefinition : ModelBase + public abstract class ProviderDefinition : ModelBase, IEquatable { + private static readonly MemberwiseEqualityComparer Comparer = MemberwiseEqualityComparer.ByFields; + protected ProviderDefinition() { Tags = new HashSet(); @@ -16,6 +20,7 @@ namespace NzbDrone.Core.ThingiProvider public string Name { get; set; } [JsonIgnore] + [MemberwiseEqualityIgnore] public string ImplementationName { get; set; } public string Implementation { get; set; } @@ -24,12 +29,10 @@ namespace NzbDrone.Core.ThingiProvider public ProviderMessage Message { get; set; } public HashSet Tags { get; set; } + [MemberwiseEqualityIgnore] public IProviderConfig Settings { - get - { - return _settings; - } + get => _settings; set { _settings = value; @@ -39,5 +42,20 @@ namespace NzbDrone.Core.ThingiProvider } } } + + public bool Equals(ProviderDefinition other) + { + return Comparer.Equals(this, other); + } + + public override bool Equals(object obj) + { + return Equals(obj as ProviderDefinition); + } + + public override int GetHashCode() + { + return Comparer.GetHashCode(this); + } } } diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs b/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs index e82ad2ab5..3b93a5464 100644 --- a/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs +++ b/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs @@ -13,8 +13,8 @@ namespace Prowlarr.Api.V1.Indexers { public class IndexerResource : ProviderResource { - public string[] IndexerUrls { get; set; } - public string[] LegacyUrls { get; set; } + public IEnumerable IndexerUrls { get; set; } + public IEnumerable LegacyUrls { get; set; } public string DefinitionName { get; set; } public string Description { get; set; } public string Language { get; set; } diff --git a/src/Prowlarr.Api.V1/ProviderControllerBase.cs b/src/Prowlarr.Api.V1/ProviderControllerBase.cs index f585e8b52..f61668d13 100644 --- a/src/Prowlarr.Api.V1/ProviderControllerBase.cs +++ b/src/Prowlarr.Api.V1/ProviderControllerBase.cs @@ -3,7 +3,6 @@ using System.Linq; using FluentValidation; using FluentValidation.Results; using Microsoft.AspNetCore.Mvc; -using NzbDrone.Common.Serializer; using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; using NzbDrone.Http.REST.Attributes; @@ -90,10 +89,8 @@ namespace Prowlarr.Api.V1 var existingDefinition = _providerFactory.Find(providerResource.Id); var providerDefinition = GetDefinition(providerResource, existingDefinition, true, !forceSave, false); - // Comparing via JSON string to eliminate the need for every provider implementation to implement equality checks. // Compare settings separately because they are not serialized with the definition. - var hasDefinitionChanged = STJson.ToJson(existingDefinition) != STJson.ToJson(providerDefinition) || - STJson.ToJson(existingDefinition.Settings) != STJson.ToJson(providerDefinition.Settings); + var hasDefinitionChanged = !existingDefinition.Equals(providerDefinition) || !existingDefinition.Settings.Equals(providerDefinition.Settings); // Only test existing definitions if it is enabled and forceSave isn't set and the definition has changed. if (providerDefinition.Enable && !forceSave && hasDefinitionChanged)