diff --git a/Gruntfile.js b/Gruntfile.js index 0dffe9882..cc86db1e6 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -21,8 +21,7 @@ module.exports = function(grunt) { handlebars: { options: { - namespace: "NzbDrone.Templates", - wrapped: false, + namespace: "Templates", processName: function(fileName){ return fileName .replace('UI/','') @@ -52,10 +51,6 @@ module.exports = function(grunt) { src: 'UI/**/*.png', dest: '_output/' }, - templates:{ - src: 'UI/**/*emplate.html', - dest: '_output/' - }, fonts:{ src: 'UI/**/Fonts/*.*', dest: '_output/', @@ -87,10 +82,6 @@ module.exports = function(grunt) { files: '<%= copy.images.src %>', tasks: ['copy:images'] }, - copyTemplates:{ - files: '<%= copy.templates.src %>', - tasks: ['copy:templates'] - }, copyFonts:{ files: '<%= copy.fonts.src %>', tasks: ['copy:fonts'] diff --git a/NzbDrone.Api.Test/NzbDrone.Api.Test.csproj b/NzbDrone.Api.Test/NzbDrone.Api.Test.csproj new file mode 100644 index 000000000..5d4582d78 --- /dev/null +++ b/NzbDrone.Api.Test/NzbDrone.Api.Test.csproj @@ -0,0 +1,91 @@ + + + + + Debug + AnyCPU + {D18A5DEB-5102-4775-A1AF-B75DAAA8907B} + Library + Properties + NzbDrone.Api.Test + NzbDrone.Api.Test + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + prompt + MinimumRecommendedRules.ruleset + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + + + + ..\packages\NUnit.2.6.2\lib\nunit.framework.dll + + + + + + + + + + + + + + + + {FD286DF8-2D3A-4394-8AD5-443FADE55FB2} + NzbDrone.Api + + + {f2be0fdf-6e47-4827-a420-dd4ef82407f8} + NzbDrone.Common + + + {CADDFCE0-7509-4430-8364-2074E1EEFCA2} + NzbDrone.Test.Common + + + + + + + + \ No newline at end of file diff --git a/NzbDrone.Api.Test/Properties/AssemblyInfo.cs b/NzbDrone.Api.Test/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..3ca19b7d7 --- /dev/null +++ b/NzbDrone.Api.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NzbDrone.Api.Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("NzbDrone.Api.Test")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("260b2ff9-d3b7-4d8a-b720-a12c93d045e5")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/NzbDrone.Api.Test/StaticResourceMapperFixture.cs b/NzbDrone.Api.Test/StaticResourceMapperFixture.cs new file mode 100644 index 000000000..90d2232b8 --- /dev/null +++ b/NzbDrone.Api.Test/StaticResourceMapperFixture.cs @@ -0,0 +1,21 @@ +using System.IO; +using NUnit.Framework; +using NzbDrone.Api.Frontend; +using NzbDrone.Test.Common; + +namespace NzbDrone.Api.Test +{ + [TestFixture] + public class StaticResourceMapperFixture : TestBase + { + [TestCase("/app.js", Result = "ui|app.js")] + [TestCase("/series/app.js", Result = "ui|series|app.js")] + [TestCase("series/app.js", Result = "ui|series|app.js")] + [TestCase("Series/App.js", Result = "ui|series|app.js")] + public string should_map_paths(string path) + { + return Subject.Map(path).Replace(Path.DirectorySeparatorChar, '|'); + } + + } +} diff --git a/NzbDrone.Api.Test/packages.config b/NzbDrone.Api.Test/packages.config new file mode 100644 index 000000000..5c3ca54dd --- /dev/null +++ b/NzbDrone.Api.Test/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/NzbDrone.Api/Directories/DirectoryModule.cs b/NzbDrone.Api/Directories/DirectoryModule.cs index 1fed2d609..8f93a1524 100644 --- a/NzbDrone.Api/Directories/DirectoryModule.cs +++ b/NzbDrone.Api/Directories/DirectoryModule.cs @@ -1,10 +1,8 @@ using System; using System.Collections.Generic; -using System.Linq; using Nancy; using NzbDrone.Api.Extensions; using NzbDrone.Common; -using NzbDrone.Core.RootFolders; namespace NzbDrone.Api.Directories { diff --git a/NzbDrone.Api/FrontendModule/IndexModule.cs b/NzbDrone.Api/Frontend/IndexModule.cs similarity index 85% rename from NzbDrone.Api/FrontendModule/IndexModule.cs rename to NzbDrone.Api/Frontend/IndexModule.cs index 45198e141..8a6e15f80 100644 --- a/NzbDrone.Api/FrontendModule/IndexModule.cs +++ b/NzbDrone.Api/Frontend/IndexModule.cs @@ -1,9 +1,7 @@ -using System; -using System.Linq; +using System; using Nancy; -using Nancy.Responses.Negotiation; -namespace NzbDrone.Api.FrontendModule +namespace NzbDrone.Api.Frontend { public class IndexModule : NancyModule { diff --git a/NzbDrone.Api/Frontend/StaticResourceMapper.cs b/NzbDrone.Api/Frontend/StaticResourceMapper.cs new file mode 100644 index 000000000..9ef688ee0 --- /dev/null +++ b/NzbDrone.Api/Frontend/StaticResourceMapper.cs @@ -0,0 +1,21 @@ +using System.IO; + +namespace NzbDrone.Api.Frontend +{ + public interface IMapHttpRequestsToDisk + { + string Map(string resourceUrl); + } + + public class StaticResourceMapper : IMapHttpRequestsToDisk + { + public string Map(string resourceUrl) + { + var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar); + path = path.Trim(Path.DirectorySeparatorChar).ToLower(); + + + return Path.Combine("ui", path); + } + } +} \ No newline at end of file diff --git a/NzbDrone.Api/Frontend/StaticResourceProvider.cs b/NzbDrone.Api/Frontend/StaticResourceProvider.cs new file mode 100644 index 000000000..f7c3c1aba --- /dev/null +++ b/NzbDrone.Api/Frontend/StaticResourceProvider.cs @@ -0,0 +1,60 @@ +using System.Linq; +using NLog; +using Nancy; +using Nancy.Responses; +using NzbDrone.Common; + +namespace NzbDrone.Api.Frontend +{ + public interface IProcessStaticResource + { + Response ProcessStaticResourceRequest(NancyContext context, string workingFolder); + } + + public class StaticResourceProvider : IProcessStaticResource + { + private readonly DiskProvider _diskProvider; + private readonly IMapHttpRequestsToDisk _requestMapper; + private readonly Logger _logger; + + public StaticResourceProvider(DiskProvider diskProvider, IMapHttpRequestsToDisk requestMapper, Logger logger) + { + _diskProvider = diskProvider; + _requestMapper = requestMapper; + _logger = logger; + } + + public Response ProcessStaticResourceRequest(NancyContext context, string workingFolder) + { + var path = context.Request.Url.Path.ToLower(); + + if (IsStaticResource(path)) + { + var filePath = _requestMapper.Map(path); + + if (_diskProvider.FileExists(filePath)) + { + return new GenericFileResponse(filePath); + } + + _logger.Warn("Couldn't find file [{0}] for [{1}]", filePath, path); + } + + return null; + } + + + private static readonly string[] Extensions = new[] { ".css", ".js", ".html", ".htm", ".jpg", ".jpeg", ".icon", ".gif", ".png", ".woff", ".ttf" }; + + + private bool IsStaticResource(string path) + { + if (string.IsNullOrWhiteSpace(path)) + { + return false; + } + + return Extensions.Any(path.EndsWith); + } + } +} \ No newline at end of file diff --git a/NzbDrone.Api/NancyBootstrapper.cs b/NzbDrone.Api/NancyBootstrapper.cs index 1c8fae5d3..4b7535f2e 100644 --- a/NzbDrone.Api/NancyBootstrapper.cs +++ b/NzbDrone.Api/NancyBootstrapper.cs @@ -2,17 +2,20 @@ using System.Collections.Generic; using Autofac; using NLog; +using Nancy; using Nancy.Bootstrapper; using Nancy.Bootstrappers.Autofac; using Nancy.Conventions; using Nancy.Diagnostics; using NzbDrone.Api.ErrorManagement; using NzbDrone.Api.Extensions; +using NzbDrone.Api.Frontend; using NzbDrone.Common; using NzbDrone.Core; using NzbDrone.Core.Configuration; using NzbDrone.Core.Lifecycle; using SignalR; +using ErrorPipeline = NzbDrone.Api.ErrorManagement.ErrorPipeline; namespace NzbDrone.Api { @@ -41,7 +44,7 @@ namespace NzbDrone.Api SignalRBootstraper.InitializeAutomapper(container); RegisterReporting(container); KickoffInitilizables(container); - + ApplicationPipelines.OnError.AddItemToEndOfPipeline(container.Resolve().HandleException); } @@ -77,7 +80,7 @@ namespace NzbDrone.Api var builder = new ContainerBuilder(); builder.RegisterCoreServices(); builder.RegisterApiServices(); - + var container = builder.Build(); return container; @@ -104,8 +107,10 @@ namespace NzbDrone.Api protected override void ConfigureConventions(NancyConventions nancyConventions) { base.ConfigureConventions(nancyConventions); - Conventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("static", @"UI", new[] { ".css", ".js", ".html", ".htm", ".jpg", ".jpeg", ".icon", ".gif", ".png", ".woff", ".ttf" })); + var processors = ApplicationContainer.Resolve(); + Conventions.StaticContentsConventions.Add(processors.ProcessStaticResourceRequest); } + } public static class SignalRBootstraper diff --git a/NzbDrone.Api/NzbDrone.Api.csproj b/NzbDrone.Api/NzbDrone.Api.csproj index 71fa895a8..75a2cf157 100644 --- a/NzbDrone.Api/NzbDrone.Api.csproj +++ b/NzbDrone.Api/NzbDrone.Api.csproj @@ -102,7 +102,9 @@ - + + + diff --git a/NzbDrone.Core.Test/Framework/CoreTest.cs b/NzbDrone.Core.Test/Framework/CoreTest.cs index 7e6a3fd5f..95985775c 100644 --- a/NzbDrone.Core.Test/Framework/CoreTest.cs +++ b/NzbDrone.Core.Test/Framework/CoreTest.cs @@ -16,12 +16,6 @@ namespace NzbDrone.Core.Test.Framework } } - protected static void ThrowException() - { - throw new ApplicationException("This is a message for test exception"); - } - - protected FileStream OpenRead(params string[] path) { return File.OpenRead(Path.Combine(path)); diff --git a/NzbDrone.Test.Common/TestBase.cs b/NzbDrone.Test.Common/TestBase.cs index 52197c3f5..f23c4f54c 100644 --- a/NzbDrone.Test.Common/TestBase.cs +++ b/NzbDrone.Test.Common/TestBase.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using System.IO; using Moq; using NLog; @@ -10,6 +9,32 @@ using NzbDrone.Test.Common.AutoMoq; namespace NzbDrone.Test.Common { + public abstract class TestBase : TestBase where TSubject : class + { + + private TSubject _subject; + + [SetUp] + public void CoreTestSetup() + { + _subject = null; + } + + protected TSubject Subject + { + get + { + if (_subject == null) + { + _subject = Mocker.Resolve(); + } + + return _subject; + } + + } + } + public abstract class TestBase : LoggingTest { protected const string INTEGRATION_TEST = "Integration Test"; diff --git a/NzbDrone.sln b/NzbDrone.sln index b7721d0c8..9fc735f04 100644 --- a/NzbDrone.sln +++ b/NzbDrone.sln @@ -42,6 +42,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Api", "NzbDrone.Ap EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Console", "NzbDrone.Console\NzbDrone.Console.csproj", "{3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Api.Test", "NzbDrone.Api.Test\NzbDrone.Api.Test.csproj", "{D18A5DEB-5102-4775-A1AF-B75DAAA8907B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 @@ -104,6 +106,10 @@ Global {3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}.Debug|x86.Build.0 = Debug|x86 {3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}.Release|x86.ActiveCfg = Release|x86 {3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}.Release|x86.Build.0 = Release|x86 + {D18A5DEB-5102-4775-A1AF-B75DAAA8907B}.Debug|x86.ActiveCfg = Debug|Any CPU + {D18A5DEB-5102-4775-A1AF-B75DAAA8907B}.Debug|x86.Build.0 = Debug|Any CPU + {D18A5DEB-5102-4775-A1AF-B75DAAA8907B}.Release|x86.ActiveCfg = Release|x86 + {D18A5DEB-5102-4775-A1AF-B75DAAA8907B}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -114,6 +120,7 @@ Global {C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5} = {57A04B72-8088-4F75-A582-1158CF8291F7} {35388E8E-0CDB-4A84-AD16-E4B6EFDA5D97} = {57A04B72-8088-4F75-A582-1158CF8291F7} {BEC74619-DDBB-4FBA-B517-D3E20AFC9997} = {57A04B72-8088-4F75-A582-1158CF8291F7} + {D18A5DEB-5102-4775-A1AF-B75DAAA8907B} = {57A04B72-8088-4F75-A582-1158CF8291F7} {FAFB5948-A222-4CF6-AD14-026BE7564802} = {47697CDB-27B6-4B05-B4F8-0CBE6F6EDF97} {CADDFCE0-7509-4430-8364-2074E1EEFCA2} = {47697CDB-27B6-4B05-B4F8-0CBE6F6EDF97} {6BCE712F-846D-4846-9D1B-A66B858DA755} = {F9E67978-5CD6-4A5F-827B-4249711C0B02} diff --git a/UI/.idea/jsLinters/jshint.xml b/UI/.idea/jsLinters/jshint.xml index 994917c7a..773318293 100644 --- a/UI/.idea/jsLinters/jshint.xml +++ b/UI/.idea/jsLinters/jshint.xml @@ -61,7 +61,7 @@ - + diff --git a/UI/Index.html b/UI/Index.html index 1ed3195e4..15af76309 100644 --- a/UI/Index.html +++ b/UI/Index.html @@ -9,32 +9,20 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + - @@ -100,27 +88,29 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - + + + + - - + +