Skip to content

Commit

Permalink
added curated feed API service
Browse files Browse the repository at this point in the history
  • Loading branch information
half-ogre committed Mar 19, 2012
1 parent 7697c51 commit 411471c
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 12 deletions.
10 changes: 5 additions & 5 deletions Facts/Services/FeedServiceFacts.cs
Expand Up @@ -22,7 +22,7 @@ public void V1FeedSearchDoesNotReturnPrereleasePackages()
configuration.SetupGet(c => c.SiteRoot).Returns("https://localhost:8081/");
var searchService = new Mock<ISearchService>(MockBehavior.Strict);
searchService.Setup(s => s.SearchWithRelevance(It.IsAny<IQueryable<Package>>(), It.IsAny<String>())).Returns<IQueryable<Package>, string>((_, __) => _);
var v1Service = new V1Feed(repo.Object, configuration.Object, searchService.Object);
var v1Service = new V1Feed(null, repo.Object, configuration.Object, searchService.Object);

// Act
var result = v1Service.Search(null, null);
Expand All @@ -49,7 +49,7 @@ public void V1FeedSearchDoesNotReturnUnlistedPackages()
searchService.Setup(s => s.SearchWithRelevance(It.IsAny<IQueryable<Package>>(), It.IsAny<String>())).Returns<IQueryable<Package>, string>((_, __) => _);
var configuration = new Mock<IConfiguration>(MockBehavior.Strict);
configuration.SetupGet(c => c.SiteRoot).Returns("http://test.nuget.org/");
var v1Service = new V1Feed(repo.Object, configuration.Object, searchService.Object);
var v1Service = new V1Feed(null, repo.Object, configuration.Object, searchService.Object);

// Act
var result = v1Service.Search(null, null);
Expand Down Expand Up @@ -77,7 +77,7 @@ public void V2FeedSearchDoesNotReturnPrereleasePackagesIfFlagIsFalse()
searchService.Setup(s => s.SearchWithRelevance(It.IsAny<IQueryable<Package>>(), It.IsAny<String>())).Returns<IQueryable<Package>, string>((_, __) => _);
var configuration = new Mock<IConfiguration>(MockBehavior.Strict);
configuration.SetupGet(c => c.SiteRoot).Returns("https://staged.nuget.org/");
var v2Service = new V2Feed(repo.Object, configuration.Object, searchService.Object);
var v2Service = new V2Feed(null, repo.Object, configuration.Object, searchService.Object);

// Act
var result = v2Service.Search(null, null, includePrerelease: false);
Expand All @@ -103,7 +103,7 @@ public void V1FeedFindPackagesByIdReturnsUnlistedPackagesButNotPrereleasePackage
}.AsQueryable());
var configuration = new Mock<IConfiguration>(MockBehavior.Strict);
configuration.SetupGet(c => c.SiteRoot).Returns("https://localhost:8081/");
var v1Service = new V1Feed(repo.Object, configuration.Object, null);
var v1Service = new V1Feed(null, repo.Object, configuration.Object, null);

// Act
var result = v1Service.FindPackagesById("Foo");
Expand All @@ -127,7 +127,7 @@ public void V2FeedFindPackagesByIdReturnsUnlistedAndPrereleasePackages()
}.AsQueryable());
var configuration = new Mock<IConfiguration>(MockBehavior.Strict);
configuration.SetupGet(c => c.SiteRoot).Returns("https://localhost:8081/");
var v2Service = new V2Feed(repo.Object, configuration.Object, null);
var v2Service = new V2Feed(null, repo.Object, configuration.Object, null);

// Act
var result = v2Service.FindPackagesById("Foo");
Expand Down
5 changes: 5 additions & 0 deletions Website/App_Start/Routes.cs
Expand Up @@ -186,6 +186,11 @@ public static void RegisterRoutes(RouteCollection routes)
defaults: null,
constraints: new { httpMethod = new HttpMethodConstraint("DELETE") });

routes.MapServiceRoute(
RouteName.V2ApiCuratedFeed,
"api/v2/curated-feed",
typeof(V2CuratedFeed));

routes.MapServiceRoute(
RouteName.V2ApiFeed,
"api/v2/",
Expand Down
17 changes: 14 additions & 3 deletions Website/DataServices/FeedServiceBase.cs
Expand Up @@ -14,26 +14,37 @@ namespace NuGetGallery
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public abstract class FeedServiceBase<TPackage> : DataService<FeedContext<TPackage>>, IDataServiceStreamProvider, IServiceProvider
{
private readonly IEntitiesContext entities;
private readonly IEntityRepository<Package> packageRepo;
private readonly IConfiguration configuration;
private readonly ISearchService searchService;

public FeedServiceBase()
: this(DependencyResolver.Current.GetService<IEntityRepository<Package>>(),
: this(DependencyResolver.Current.GetService<IEntitiesContext>(),
DependencyResolver.Current.GetService<IEntityRepository<Package>>(),
DependencyResolver.Current.GetService<IConfiguration>(),
DependencyResolver.Current.GetService<ISearchService>())
{

}

protected FeedServiceBase(IEntityRepository<Package> packageRepo, IConfiguration configuration, ISearchService searchService)
protected FeedServiceBase(
IEntitiesContext entities,
IEntityRepository<Package> packageRepo,
IConfiguration configuration,
ISearchService searchService)
{
// TODO: See if there is a way to do proper DI with data services
this.entities = entities;
this.packageRepo = packageRepo;
this.configuration = configuration;
this.searchService = searchService;
}

protected IEntitiesContext Entities
{
get { return entities; }
}

protected IEntityRepository<Package> PackageRepo
{
get { return packageRepo; }
Expand Down
4 changes: 2 additions & 2 deletions Website/DataServices/V1Feed.svc.cs
Expand Up @@ -17,8 +17,8 @@ public V1Feed()

}

public V1Feed(IEntityRepository<Package> repo, IConfiguration configuration, ISearchService searchSvc)
: base(repo, configuration, searchSvc)
public V1Feed(IEntitiesContext entities, IEntityRepository<Package> repo, IConfiguration configuration, ISearchService searchSvc)
: base(entities, repo, configuration, searchSvc)
{

}
Expand Down
1 change: 1 addition & 0 deletions Website/DataServices/V2CuratedFeed.svc
@@ -0,0 +1 @@
<%@ ServiceHost Language="C#" Debug="true" Service="NuGetGallery.V2Feed" CodeBehind="V2CuratedFeed.svc.cs" %>
82 changes: 82 additions & 0 deletions Website/DataServices/V2CuratedFeed.svc.cs
@@ -0,0 +1,82 @@
using System;
using System.Data.Entity;
using System.Data.Services;
using System.Linq;
using System.ServiceModel.Web;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace NuGetGallery
{
public class V2CuratedFeed : FeedServiceBase<V2FeedPackage>
{
private const int FeedVersion = 2;

public V2CuratedFeed()
{

}

public V2CuratedFeed(IEntitiesContext entities, IEntityRepository<Package> repo, IConfiguration configuration, ISearchService searchSvc)
: base(entities, repo, configuration, searchSvc)
{
}

protected override FeedContext<V2FeedPackage> CreateDataSource()
{
var packages = GetPackages();

return new FeedContext<V2FeedPackage>
{
Packages = packages.ToV2FeedPackageQuery(Configuration.SiteRoot)
};
}

[WebGet]
public IQueryable<V2FeedPackage> FindPackagesById(string id)
{
return GetPackages()
.Where(p => p.PackageRegistration.Id.Equals(id, StringComparison.OrdinalIgnoreCase))
.ToV2FeedPackageQuery(Configuration.SiteRoot);
}

public IQueryable<Package> GetPackages()
{
string curatedFeed = HttpContext.Current.Request.QueryString["name"];
if (curatedFeed == null)
throw new Exception();

return Entities.CuratedFeeds
.Where(cf => cf.Name == curatedFeed)
.Include(cf => cf.Packages.Select(cp => cp.PackageRegistration.Packages))
.SelectMany(cf => cf.Packages.SelectMany(cp => cp.PackageRegistration.Packages.Select(p => p)));
}

[WebGet]
public IQueryable<V2FeedPackage> Search(string searchTerm, string targetFramework, bool includePrerelease)
{
var packages = GetPackages();

packages = packages.Where(p => p.Listed);
if (!includePrerelease)
{
packages = packages.Where(p => !p.IsPrerelease);
}
return packages.Search(searchTerm).ToV2FeedPackageQuery(Configuration.SiteRoot);
}

public override Uri GetReadStreamUri(
object entity,
DataServiceOperationContext operationContext)
{
var package = (V2FeedPackage)entity;
var httpContext = new HttpContextWrapper(HttpContext.Current);
var urlHelper = new UrlHelper(new RequestContext(httpContext, new RouteData()));

string url = urlHelper.PackageDownload(FeedVersion, package.Id, package.Version);

return new Uri(url, UriKind.Absolute);
}
}
}
4 changes: 2 additions & 2 deletions Website/DataServices/V2Feed.svc.cs
Expand Up @@ -18,8 +18,8 @@ public V2Feed()

}

public V2Feed(IEntityRepository<Package> repo, IConfiguration configuration, ISearchService searchSvc)
: base(repo, configuration, searchSvc)
public V2Feed(IEntitiesContext entities, IEntityRepository<Package> repo, IConfiguration configuration, ISearchService searchSvc)
: base(entities, repo, configuration, searchSvc)
{

}
Expand Down
1 change: 1 addition & 0 deletions Website/RouteNames.cs
Expand Up @@ -2,6 +2,7 @@
{
public static class RouteName
{
public const string V2ApiCuratedFeed = "V2ApiCuratedFeed";
public const string V1ApiFeed = "V1ApiFeed";
public const string V2ApiFeed = "V2ApiFeed";
public const string ApiFeed = "ApiFeed";
Expand Down
4 changes: 4 additions & 0 deletions Website/Website.csproj
Expand Up @@ -169,6 +169,9 @@
<Compile Include="Controllers\AppController.cs" />
<Compile Include="Controllers\CuratedFeedsController.cs" />
<Compile Include="Controllers\CuratedPackagesController.cs" />
<Compile Include="DataServices\V2CuratedFeed.svc.cs">
<DependentUpon>V2CuratedFeed.svc</DependentUpon>
</Compile>
<Compile Include="DataServices\V1FeedPackage.cs">
<SubType>Code</SubType>
</Compile>
Expand Down Expand Up @@ -683,6 +686,7 @@
<Content Include="Content\Images\userIconWhite.png" />
<Content Include="Content\Images\xmark.png" />
<Content Include="Content\Images\sendMessageGraphic.png" />
<Content Include="DataServices\V2CuratedFeed.svc" />
<Content Include="DataServices\V1Feed.svc" />
<Content Include="DataServices\V2Feed.svc" />
<Content Include="DynamicData\Content\GridViewPager.ascx" />
Expand Down

0 comments on commit 411471c

Please sign in to comment.