diff --git a/.gitignore b/.gitignore index 05b52a64e..acbce3bc6 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ _ReSharper*/ [Nn]zbs [Bb]uild/ [Ll]ogs/ +[Aa]pp_Data/ /[Pp]ackage/ #NZBDrone specific *.db diff --git a/NzbDrone.Core.Test/ConfigFileProviderTest.cs b/NzbDrone.Core.Test/ConfigFileProviderTest.cs index 7c6496aba..471bec774 100644 --- a/NzbDrone.Core.Test/ConfigFileProviderTest.cs +++ b/NzbDrone.Core.Test/ConfigFileProviderTest.cs @@ -1,4 +1,5 @@ -using AutoMoq; +using System.IO; +using AutoMoq; using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.Providers.Core; @@ -11,6 +12,17 @@ namespace NzbDrone.Core.Test // ReSharper disable InconsistentNaming public class ConfigFileProviderTest : TestBase { + [SetUp] + public void SetUp() + { + //Reset config file + var mocker = new AutoMoqer(); + var configFile = mocker.Resolve().ConfigFile; + File.Delete(configFile); + + mocker.Resolve().CreateDefaultConfigFile(); + } + [Test] public void GetValue_Success() { @@ -80,5 +92,37 @@ namespace NzbDrone.Core.Test //Assert result.Should().Be(value); } + + [Test] + public void SetValue_bool() + { + const string key = "LaunchBrowser"; + const bool value = false; + + var mocker = new AutoMoqer(); + + //Act + mocker.Resolve().SetValue(key, value); + + //Assert + var result = mocker.Resolve().LaunchBrowser; + result.Should().Be(value); + } + + [Test] + public void SetValue_int() + { + const string key = "Port"; + const int value = 12345; + + var mocker = new AutoMoqer(); + + //Act + mocker.Resolve().SetValue(key, value); + + //Assert + var result = mocker.Resolve().Port; + result.Should().Be(value); + } } } \ No newline at end of file diff --git a/NzbDrone.Core/CentralDispatch.cs b/NzbDrone.Core/CentralDispatch.cs index c255d1062..ca707daa5 100644 --- a/NzbDrone.Core/CentralDispatch.cs +++ b/NzbDrone.Core/CentralDispatch.cs @@ -9,6 +9,7 @@ using NLog; using NzbDrone.Core.Datastore; using NzbDrone.Core.Instrumentation; using NzbDrone.Core.Providers; +using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.ExternalNotification; using NzbDrone.Core.Providers.Indexer; using NzbDrone.Core.Providers.Jobs; @@ -62,6 +63,7 @@ namespace NzbDrone.Core _kernel.Get().SetupDefaultProfiles(); _kernel.Get().SetupDefault(); + _kernel.Get().CreateDefaultConfigFile(); BindExternalNotifications(); BindIndexers(); diff --git a/NzbDrone.Core/Providers/Core/ConfigFileProvider.cs b/NzbDrone.Core/Providers/Core/ConfigFileProvider.cs index a7daa4bc6..193c126a3 100644 --- a/NzbDrone.Core/Providers/Core/ConfigFileProvider.cs +++ b/NzbDrone.Core/Providers/Core/ConfigFileProvider.cs @@ -18,11 +18,13 @@ namespace NzbDrone.Core.Providers.Core public virtual int Port { get { return GetValueInt("Port"); } + set { SetValue("Port", value); } } public virtual bool LaunchBrowser { get { return GetValueBoolean("LaunchBrowser"); } + set { SetValue("LaunchBrowser", value); } } public virtual string GetValue(string key, string parent = null) @@ -32,7 +34,7 @@ namespace NzbDrone.Core.Providers.Core var parentContainer = config; - if (parent != null) + if (!String.IsNullOrEmpty(parent)) parentContainer = config.Descendants(parent).Single(); var value = parentContainer.Descendants(key).Single().Value; @@ -49,5 +51,44 @@ namespace NzbDrone.Core.Providers.Core { return Convert.ToBoolean(GetValue(key, parent)); } + + public virtual void SetValue(string key, object value, string parent = null) + { + var xDoc = XDocument.Load(ConfigFile); + var config = xDoc.Descendants("Config").Single(); + + var parentContainer = config; + + if (!String.IsNullOrEmpty(parent)) + parentContainer = config.Descendants(parent).Single(); + + parentContainer.Descendants(key).Single().Value = value.ToString(); + + xDoc.Save(ConfigFile); + } + + public virtual void CreateDefaultConfigFile() + { + //Create the config file here + Directory.CreateDirectory(Path.Combine(CentralDispatch.AppPath, "App_Data")); + + if (!File.Exists(ConfigFile)) + { + WriteDefaultConfig(); + } + } + + public virtual void WriteDefaultConfig() + { + var xDoc = new XDocument(new XDeclaration("1.0", "utf-8", "yes")); + + xDoc.Add(new XElement("Config", + new XElement("Port", 8989), + new XElement("LaunchBrowser", true) + ) + ); + + xDoc.Save(ConfigFile); + } } } diff --git a/NzbDrone.Web/Controllers/SettingsController.cs b/NzbDrone.Web/Controllers/SettingsController.cs index b31666f57..0620b792c 100644 --- a/NzbDrone.Web/Controllers/SettingsController.cs +++ b/NzbDrone.Web/Controllers/SettingsController.cs @@ -29,15 +29,18 @@ namespace NzbDrone.Web.Controllers private readonly ExternalNotificationProvider _externalNotificationProvider; private readonly QualityTypeProvider _qualityTypeProvider; private readonly RootDirProvider _rootDirProvider; + private readonly ConfigFileProvider _configFileProvider; public SettingsController(ConfigProvider configProvider, IndexerProvider indexerProvider, QualityProvider qualityProvider, AutoConfigureProvider autoConfigureProvider, SeriesProvider seriesProvider, ExternalNotificationProvider externalNotificationProvider, - QualityTypeProvider qualityTypeProvider, RootDirProvider rootDirProvider) + QualityTypeProvider qualityTypeProvider, RootDirProvider rootDirProvider, + ConfigFileProvider configFileProvider) { _externalNotificationProvider = externalNotificationProvider; _qualityTypeProvider = qualityTypeProvider; _rootDirProvider = rootDirProvider; + _configFileProvider = configFileProvider; _configProvider = configProvider; _indexerProvider = indexerProvider; _qualityProvider = qualityProvider; @@ -184,6 +187,15 @@ namespace NzbDrone.Web.Controllers return View(model); } + public ActionResult System() + { + var model = new SystemSettingsModel(); + model.Port = _configFileProvider.Port; + model.LaunchBrowser = _configFileProvider.LaunchBrowser; + + return View(model); + } + public ViewResult AddProfile() { var qualityTypes = new List(); @@ -436,6 +448,20 @@ namespace NzbDrone.Web.Controllers return GetInvalidModelResult(); } + [HttpPost] + public JsonResult SaveSystem(SystemSettingsModel data) + { + if (ModelState.IsValid) + { + _configFileProvider.Port = data.Port; + _configFileProvider.LaunchBrowser = data.LaunchBrowser; + + return GetSuccessResult(); + } + + return GetInvalidModelResult(); + } + private JsonResult GetSuccessResult() { return Json(new NotificationResult() { Title = "Settings Saved" }); diff --git a/NzbDrone.Web/Models/SystemSettingsModel.cs b/NzbDrone.Web/Models/SystemSettingsModel.cs new file mode 100644 index 000000000..25615eb77 --- /dev/null +++ b/NzbDrone.Web/Models/SystemSettingsModel.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Web; + +namespace NzbDrone.Web.Models +{ + public class SystemSettingsModel + { + [DisplayName("Port")] + [Description("Port that NzbDrone runs on")] + [Range(1, 65535, ErrorMessage = "Port must be between 1 and 65535")] + public int Port { get; set; } + + [DisplayName("Launch Browser")] + [Description("Start default webrowser when NzbDrone starts?")] + public bool LaunchBrowser { get; set; } + } +} \ No newline at end of file diff --git a/NzbDrone.Web/NzbDrone.Web.csproj b/NzbDrone.Web/NzbDrone.Web.csproj index 9dc7aea0a..39eb8d0f4 100644 --- a/NzbDrone.Web/NzbDrone.Web.csproj +++ b/NzbDrone.Web/NzbDrone.Web.csproj @@ -510,6 +510,7 @@ + @@ -923,6 +924,9 @@ EditorLocalization.bg-BG.designer.cs + + +