replaced most of ServiceStack with nancy.

This commit is contained in:
Keivan Beigi 2013-01-18 17:27:30 -08:00 committed by kay.one
parent 936886f213
commit acef97b79f
22 changed files with 15057 additions and 334 deletions

View File

@ -1,39 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web;
using Autofac;
using Funq;
using NzbDrone.Api.QualityProfiles;
using NzbDrone.Api.QualityType;
using ServiceStack.WebHost.Endpoints;
using QualityProfileService = NzbDrone.Api.QualityProfiles.QualityProfileService;
namespace NzbDrone.Api
{
public class AppHost : AppHostBase
{
private IContainer _container;
public AppHost(IContainer container) //Tell ServiceStack the name and where to find your web services
: base("NzbDrone API", typeof(QualityProfileService).Assembly)
{
_container = container;
}
public override void Configure(Container container)
{
container.Adapter = new AutofacIocAdapter(_container);
SetConfig(new EndpointHostConfig { ServiceStackHandlerFactoryPath = "api" });
Routes
.Add<QualityProfileModel>("/qualityprofiles")
.Add<QualityProfileModel>("/qualityprofiles/{Id}")
.Add<QualityTypeModel>("/qualitytypes")
.Add<QualityTypeModel>("/qualitytypes/{Id}");
Bootstrapper.Initialize();
}
}
}

View File

@ -1,36 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Autofac;
using ServiceStack.Configuration;
namespace NzbDrone.Api
{
public class AutofacIocAdapter : IContainerAdapter
{
private readonly IContainer _container;
public AutofacIocAdapter(IContainer container)
{
_container = container;
}
public T Resolve<T>()
{
return _container.Resolve<T>();
}
public T TryResolve<T>()
{
T result;
if (_container.TryResolve<T>(out result))
{
return result;
}
return default(T);
}
}
}

View File

@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NzbDrone.Api.Exceptions;
using NzbDrone.Api.Helpers;
using NzbDrone.Core.Providers.Core;
using ServiceStack.ServiceHost;
using ServiceStack.ServiceInterface;
namespace NzbDrone.Api.Filters
{
public class ValidApiRequestAttribute : Attribute, IHasRequestFilter
{
public ApplyTo ApplyTo { get; set; }
public int Priority { get; set; }
public ConfigProvider _configProvider;
public void RequestFilter(IHttpRequest req, IHttpResponse res, object requestDto)
{
//Verify the API Key here
var apikey = req.GetApiKey();
//if (String.IsNullOrWhiteSpace(apikey))
//throw new InvalidApiKeyException();
}
public IHasRequestFilter Copy()
{
return (IHasRequestFilter)this.MemberwiseClone();
}
}
}

View File

@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ServiceStack.Common.Web;
using ServiceStack.ServiceHost;
namespace NzbDrone.Api.Helpers
{
public static class HttpRequestExtensions
{
public static string GetApiKey(this IHttpRequest httpReq)
{
var auth = httpReq.Headers[HttpHeaders.Authorization];
if (auth == null) return null;
var split = auth.Split(' ');
if (split.Count() != 2)
return null;
if (!split[0].Equals("APIKEY", StringComparison.InvariantCultureIgnoreCase))
return null;
return split[1];
}
}
}

View File

@ -1,9 +0,0 @@
using System.Linq;
namespace NzbDrone.Api
{
public interface IApiRequest
{
string ApiKey { get; set; }
}
}

View File

@ -59,29 +59,18 @@
<Reference Include="AutoMapper">
<HintPath>..\packages\AutoMapper.2.2.0\lib\net40\AutoMapper.dll</HintPath>
</Reference>
<Reference Include="ServiceStack">
<HintPath>..\packages\ServiceStack.3.9.25\lib\net35\ServiceStack.dll</HintPath>
<Reference Include="Nancy">
<HintPath>..\packages\Nancy.0.15.3\lib\net40\Nancy.dll</HintPath>
</Reference>
<Reference Include="ServiceStack.Common">
<HintPath>..\packages\ServiceStack.Common.3.9.25\lib\net35\ServiceStack.Common.dll</HintPath>
<Reference Include="Nancy.Bootstrappers.Autofac">
<HintPath>..\packages\Nancy.Bootstrappers.Autofac.0.15.3\lib\net40\Nancy.Bootstrappers.Autofac.dll</HintPath>
</Reference>
<Reference Include="ServiceStack.Interfaces">
<HintPath>..\packages\ServiceStack.Common.3.9.25\lib\net35\ServiceStack.Interfaces.dll</HintPath>
<Reference Include="Nancy.Hosting.Aspnet">
<HintPath>..\packages\Nancy.Hosting.Aspnet.0.15.3\lib\net40\Nancy.Hosting.Aspnet.dll</HintPath>
</Reference>
<Reference Include="ServiceStack.OrmLite">
<HintPath>..\packages\ServiceStack.OrmLite.SqlServer.3.9.26\lib\ServiceStack.OrmLite.dll</HintPath>
</Reference>
<Reference Include="ServiceStack.OrmLite.SqlServer">
<HintPath>..\packages\ServiceStack.OrmLite.SqlServer.3.9.26\lib\ServiceStack.OrmLite.SqlServer.dll</HintPath>
</Reference>
<Reference Include="ServiceStack.Redis">
<HintPath>..\packages\ServiceStack.Redis.3.9.25\lib\net35\ServiceStack.Redis.dll</HintPath>
</Reference>
<Reference Include="ServiceStack.ServiceInterface">
<HintPath>..\packages\ServiceStack.3.9.25\lib\net35\ServiceStack.ServiceInterface.dll</HintPath>
</Reference>
<Reference Include="ServiceStack.Text">
<HintPath>..\packages\ServiceStack.Text.3.9.27\lib\net35\ServiceStack.Text.dll</HintPath>
<Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@ -92,19 +81,14 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="AppHost.cs" />
<Compile Include="AutofacContainerAdapter.cs" />
<Compile Include="Bootstrapper.cs" />
<Compile Include="Exceptions\InvalidApiKeyException.cs" />
<Compile Include="Filters\ValidApiRequestAttribute.cs" />
<Compile Include="Helpers\HttpRequestExtensions.cs" />
<Compile Include="IApiRequest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="QualityProfiles\QualityProfileModel.cs" />
<Compile Include="QualityProfiles\QualityProfileService.cs" />
<Compile Include="QualityProfiles\QualityProfileType.cs" />
<Compile Include="QualityProfiles\QualityProfileModule.cs" />
<Compile Include="QualityType\QualityTypeModel.cs" />
<Compile Include="QualityType\QualityTypeService.cs" />
<Compile Include="QualityType\QualityTypeModule.cs" />
<Compile Include="QualityType\RequestExtensions.cs" />
<Compile Include="Resolvers\AllowedToQualitiesResolver.cs" />
<Compile Include="Resolvers\QualitiesToAllowedResolver.cs" />
<Compile Include="Resolvers\QualityTypesToIntResolver.cs" />

View File

@ -12,4 +12,12 @@ namespace NzbDrone.Api.QualityProfiles
public Int32 Cutoff { get; set; }
public List<QualityProfileType> Qualities { get; set; }
}
public class QualityProfileType
{
public Int32 Id { get; set; }
public Int32 Weight { get; set; }
public String Name { get; set; }
public Boolean Allowed { get; set; }
}
}

View File

@ -0,0 +1,66 @@
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
using Nancy;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository.Quality;
using NzbDrone.Api.QualityType;
namespace NzbDrone.Api.QualityProfiles
{
public class QualityProfileModule : NancyModule
{
private readonly QualityProvider _qualityProvider;
public QualityProfileModule(QualityProvider qualityProvider)
{
_qualityProvider = qualityProvider;
}
public QualityProfileModule()
: base("/QualityProfile")
{
Get["/"] = x => OnGet();
Get["/{Id}"] = x => OnGet((int)x.Id);
Put["/"] = x => OnPut();
Delete["/{Id}"] = x => OnDelete((int)x.Id);
}
private Response OnGet()
{
var profiles = _qualityProvider.All();
return Mapper.Map<List<QualityProfile>, List<QualityProfileModel>>(profiles).AsResponse();
}
private Response OnGet(int id)
{
var profile = _qualityProvider.Get(id);
return Mapper.Map<QualityProfile, QualityProfileModel>(profile).AsResponse();
}
private Response OnPost()
{
var request = Request.Body.FromJson<QualityProfileModel>();
var profile = Mapper.Map<QualityProfileModel, QualityProfile>(request);
request.Id = _qualityProvider.Add(profile);
return request.AsResponse();
}
//Update
private Response OnPut()
{
var request = Request.Body.FromJson<QualityProfileModel>();
var profile = Mapper.Map<QualityProfileModel, QualityProfile>(request);
_qualityProvider.Update(profile);
return request.AsResponse();
}
private Response OnDelete(int id)
{
_qualityProvider.Delete(id);
return new Response();
}
}
}

View File

@ -1,62 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
using NzbDrone.Api.Filters;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository.Quality;
using ServiceStack.ServiceInterface;
namespace NzbDrone.Api.QualityProfiles
{
[ValidApiRequest]
public class QualityProfileService : RestServiceBase<QualityProfileModel>
{
private readonly QualityProvider _qualityProvider;
public QualityProfileService(QualityProvider qualityProvider)
{
_qualityProvider = qualityProvider;
}
public QualityProfileService()
{
}
public override object OnGet(QualityProfileModel request)
{
if (request.Id == 0)
{
var profiles = _qualityProvider.All();
return Mapper.Map<List<QualityProfile>, List<QualityProfileModel>>(profiles);
}
var profile = _qualityProvider.Get(request.Id);
return Mapper.Map<QualityProfile, QualityProfileModel>(profile);
}
//Create
public override object OnPost(QualityProfileModel request)
{
var profile = Mapper.Map<QualityProfileModel, QualityProfile>(request);
request.Id = _qualityProvider.Add(profile);
return request;
}
//Update
public override object OnPut(QualityProfileModel request)
{
var profile = Mapper.Map<QualityProfileModel, QualityProfile>(request);
_qualityProvider.Update(profile);
return request;
}
public override object OnDelete(QualityProfileModel request)
{
_qualityProvider.Delete(request.Id);
return request.Id.ToString();
}
}
}

View File

@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Api.QualityProfiles
{
public class QualityProfileType
{
public Int32 Id { get; set; }
public Int32 Weight { get; set; }
public String Name { get; set; }
public Boolean Allowed { get; set; }
}
}

View File

@ -0,0 +1,52 @@
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
using Nancy;
using NzbDrone.Core.Providers;
namespace NzbDrone.Api.QualityType
{
public class QualityTypeModule : NancyModule
{
private readonly QualityTypeProvider _qualityTypeProvider;
public QualityTypeModule(QualityTypeProvider qualityTypeProvider)
{
_qualityTypeProvider = qualityTypeProvider;
}
public QualityTypeModule()
: base("/QualityTypes")
{
Get["/"] = x => GetQualityType();
Get["/{id}"] = x => GetQualityType(x.Id);
Put["/"] = x => PutQualityType();
}
private Response PutQualityType()
{
var model = Request.Body.FromJson<QualityTypeModel>();
var type = Mapper.Map<QualityTypeModel, Core.Repository.Quality.QualityType>(model);
_qualityTypeProvider.Update(type);
return model.AsResponse();
}
private Response GetQualityType(int id)
{
var type = _qualityTypeProvider.Get(id);
return Mapper.Map<Core.Repository.Quality.QualityType, QualityTypeModel>(type).AsResponse();
}
private Response GetQualityType()
{
var types = _qualityTypeProvider.All().Where(qualityType => qualityType.QualityTypeId != 0 && qualityType.QualityTypeId != 10).ToList();
var responseModel = Mapper.Map<List<Core.Repository.Quality.QualityType>, List<QualityTypeModel>>(types);
return responseModel.AsResponse();
}
}
}

View File

@ -1,57 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
using NzbDrone.Api.Filters;
using NzbDrone.Core.Providers;
using ServiceStack.ServiceInterface;
namespace NzbDrone.Api.QualityType
{
[ValidApiRequest]
public class QualityTypeService : RestServiceBase<QualityTypeModel>
{
private readonly QualityTypeProvider _qualityTypeProvider;
public QualityTypeService(QualityTypeProvider qualityTypeProvider)
{
_qualityTypeProvider = qualityTypeProvider;
}
public QualityTypeService()
{
}
public override object OnGet(QualityTypeModel request)
{
if (request.Id == 0)
{
var types = _qualityTypeProvider.All().Where(qualityType => qualityType.QualityTypeId != 0 && qualityType.QualityTypeId != 10).ToList();
return Mapper.Map<List<Core.Repository.Quality.QualityType>, List<QualityTypeModel>>(types);
}
var type = _qualityTypeProvider.Get(request.Id);
return Mapper.Map<Core.Repository.Quality.QualityType, QualityTypeModel>(type);
}
//Create
public override object OnPost(QualityTypeModel request)
{
throw new NotImplementedException();
}
//Update
public override object OnPut(QualityTypeModel request)
{
var type = Mapper.Map<QualityTypeModel, Core.Repository.Quality.QualityType>(request);
_qualityTypeProvider.Update(type);
return request;
}
public override object OnDelete(QualityTypeModel request)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.IO;
using System.Linq;
using Nancy;
using Nancy.Responses;
using Newtonsoft.Json;
namespace NzbDrone.Api.QualityType
{
public static class JsonExtensions
{
public static T FromJson<T>(this Stream body)
{
var reader = new StreamReader(body, true);
body.Position = 0;
var value = reader.ReadToEnd();
return JsonConvert.DeserializeObject<T>(value, new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
MissingMemberHandling = MissingMemberHandling.Ignore
});
}
public static Response AsResponse<TModel>(this TModel model, HttpStatusCode statusCode = HttpStatusCode.OK)
{
ISerializer serializer = new DefaultJsonSerializer();
var jsonResponse = new JsonResponse<TModel>(model, serializer) {StatusCode = statusCode};
return jsonResponse;
}
}
}

View File

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AutoMapper;
using NzbDrone.Api.QualityProfiles;
using NzbDrone.Core.Repository.Quality;

View File

@ -2,9 +2,8 @@
<packages>
<package id="Autofac" version="2.6.3.862" targetFramework="net40" />
<package id="AutoMapper" version="2.2.0" targetFramework="net40" />
<package id="ServiceStack" version="3.9.25" targetFramework="net40" />
<package id="ServiceStack.Common" version="3.9.25" targetFramework="net40" />
<package id="ServiceStack.OrmLite.SqlServer" version="3.9.26" targetFramework="net40" />
<package id="ServiceStack.Redis" version="3.9.25" targetFramework="net40" />
<package id="ServiceStack.Text" version="3.9.27" targetFramework="net40" />
<package id="Nancy" version="0.15.3" targetFramework="net40" />
<package id="Nancy.Bootstrappers.Autofac" version="0.15.3" targetFramework="net40" />
<package id="Nancy.Hosting.Aspnet" version="0.15.3" targetFramework="net40" />
<package id="Newtonsoft.Json" version="4.5.11" targetFramework="net40" />
</packages>

View File

@ -1,11 +1,83 @@
NzbDrone.AddSeriesView = Backbone.Marionette.ItemView.extend({
template: "#add-series-template"
template: "#add-series",
events: {
'click #add-new': 'addNew',
'click #add-existing': 'addExisting'
},
addNew: function () {
NzbDrone.Router.navigate(NzbDrone.Routes.Series.AddNew, { trigger: true });
},
addExisting: function () {
NzbDrone.Router.navigate(NzbDrone.Routes.Series.AddExisting, { trigger: true });
}
});
NzbDrone.AddNewSeriesView = Backbone.Marionette.ItemView.extend({
template: "#add-new-series-template"
template: "#add-new-series",
ui: {
seriesSearch: '#series-search'
},
onRender: function () {
console.log('binding auto complete')
var self = this;
this.ui.seriesSearch
.autocomplete({
source: "http://kayone.nzbdrone.com:8989/AddSeries/LookupSeries",
minLength: 1,
delay: 500,
select: function (event, ui) {
$(this).val(ui.item.Title);
$(this).siblings('.seriesId').val(ui.item.Id);
return false;
},
open: function (event, ui) {
$('.ui-autocomplete').addClass('seriesLookupResults');
},
close: function (event, ui) {
$('.ui-autocomplete').removeClass('seriesLookupResults');
}
})
.data("autocomplete")._renderItem = function (ul, item) {
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a>" + item.DisplayedTitle + "<img src='../../Content/Images/thetvdb.png' class='tvDbLink' title='Click to see series details from TheTVDB' rel='" + item.Url + "' /></a>")
.appendTo(ul);
};
},
});
NzbDrone.AddExistingSeriesView = Backbone.Marionette.ItemView.extend({
template: "#add-existing-series-template"
});
template: "#add-existing-series",
events: {
'click #single': 'single',
'click #multiple': 'multiple'
},
single: function () {
NzbDrone.Router.navigate(NzbDrone.Routes.Series.AddExistingSingle, { trigger: true });
},
multiple: function () {
NzbDrone.Router.navigate(NzbDrone.Routes.Series.AddExistingMultiple, { trigger: true });
}
});
NzbDrone.AddExistingSeriesSingleView = Backbone.Marionette.ItemView.extend({
template: "#add-existing-series-single"
});
NzbDrone.AddExistingSeriesMultipleView = Backbone.Marionette.ItemView.extend({
template: "#add-existing-series-multiple"
})

File diff suppressed because it is too large Load Diff

View File

@ -46,6 +46,7 @@
<None Include="JsLibraries\jquery-1.8.2.intellisense.js" />
<Content Include="JsLibraries\backbone.marionette.js" />
<Content Include="JsLibraries\jquery-1.8.2.js" />
<Content Include="JsLibraries\jquery-ui-1.9.0.js" />
<Content Include="JsLibraries\underscore.js" />
<Content Include="Web.config" />
</ItemGroup>

View File

@ -1,6 +1,27 @@
NzbDrone = new Backbone.Marionette.Application();
NzbDrone.Controller = {
NzbDrone.Constants = {
};
NzbDrone.Events = {
DisplayInMainRegion: "DisplayInMainRegion",
};
NzbDrone.Routes = {
Series: {
Add: 'series/add',
AddNew: 'series/addnew',
AddExisting: 'series/addExisting',
AddExistingSingle: 'series/addExisting/single',
AddExistingMultiple: 'series/addExisting/multiple',
},
};
NzbDrone.Controller = Backbone.Marionette.Controller.extend({
AddSeries: function () {
NzbDrone.mainRegion.show(new NzbDrone.AddSeriesView());
@ -9,21 +30,33 @@ NzbDrone.Controller = {
AddNewSeries: function () {
NzbDrone.mainRegion.show(new NzbDrone.AddNewSeriesView());
},
AddExistingSeries: function () {
NzbDrone.mainRegion.show(new NzbDrone.AddExistingSeriesView());
}
};
},
AddExistingSeriesSingle: function () {
NzbDrone.mainRegion.show(new NzbDrone.AddExistingSeriesSingleView());
},
AddExistingSeriesMultiple: function () {
NzbDrone.mainRegion.show(new NzbDrone.AddExistingSeriesMultipleView());
},
});
NzbDrone.MyRouter = Backbone.Marionette.AppRouter.extend({
controller: NzbDrone.Controller,
controller: new NzbDrone.Controller(),
// "someMethod" must exist at controller.someMethod
appRoutes: {
"add": "AddSeries",
"add/new": "AddNewSeries",
"add/existing": "AddExistingSeries",
"series/add": "AddSeries",
"series/addnew": "AddNewSeries",
"series/addExisting": "AddExistingSeries",
"series/addExisting/single": "AddExistingSeriesSingle",
"series/addExisting/multiple": "AddExistingSeriesMultiple",
}
});
@ -31,12 +64,12 @@ NzbDrone.MyRouter = Backbone.Marionette.AppRouter.extend({
NzbDrone.addInitializer(function (options) {
console.log("starting application");
NzbDrone.addRegions({
mainRegion: "#main-region",
});
NzbDrone.Router = new NzbDrone.MyRouter();
Backbone.history.start();

View File

@ -5,19 +5,36 @@
</head>
<body>
<div style="display: none">
<div id="add-series-template">
<h1>Add</h1>
<div id="add-series">
<h1 id="add-new">New</h1>
<h1 id="add-existing">Existing</h1>
</div>
<div id="add-existing-series-template">
<div id="add-existing-series">
<h1>Add Existing</h1>
<h2 id="single">Single Series</h2>
<h2 id="multiple">All of my series</h2>
</div>
<div id="add-new-series-template">
<div id="add-new-series">
<h1>Add New</h1>
<div class="well">
<input type="text" id="series-search" name="series-search" placeholder="Search for a series to add ..." class="span12" autocomplete="off" />
</div>
</div>
<div id="add-existing-series-single">
<h1>single
</h1>
</div>
<div id="add-existing-series-multiple">
<h1>multiple</h1>
</div>
</div>
<div id="main-region"></div>
<script src="JsLibraries/jquery-1.8.2.js" type="text/javascript"></script>
<script src="JsLibraries/jquery-ui-1.9.0.js" type="text/javascript"></script>
<script src="JsLibraries/underscore.js" type="text/javascript"></script>
<script src="JsLibraries/backbone.js" type="text/javascript"></script>
<script src="JsLibraries/backbone.marionette.js" type="text/javascript"></script>

View File

@ -85,7 +85,6 @@ namespace NzbDrone.Web
//ServiceStack
dispatch.ContainerBuilder.RegisterType<MemoryCacheClient>().As<ICacheClient>().SingleInstance();
dispatch.ContainerBuilder.RegisterType<SessionFactory>().As<ISessionFactory>().SingleInstance();
new AppHost(container).Init();
}
private static void MVCRegistration(ContainerBuilder builder)

View File

@ -1,6 +1,6 @@
<SolutionConfiguration>
<FileVersion>1</FileVersion>
<AutoEnableOnStartup>True</AutoEnableOnStartup>
<AutoEnableOnStartup>False</AutoEnableOnStartup>
<AllowParallelTestExecution>false</AllowParallelTestExecution>
<AllowTestsToRunInParallelWithThemselves>true</AllowTestsToRunInParallelWithThemselves>
<FrameworkUtilisationTypeForNUnit>UseDynamicAnalysis</FrameworkUtilisationTypeForNUnit>