Permalink
Browse files

added the automatic package curation for WebMatrix-compatible packages

  • Loading branch information...
1 parent 7ce2e08 commit eb7021123a6d1391d4bbcd81f3de8a431d375704 @half-ogre half-ogre committed Mar 19, 2012
View
50 Facts/Commands/AutomaticallyCuratePackageCommandFacts.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Moq;
+using NuGet;
+using Xunit;
+
+namespace NuGetGallery.Commands
+{
+ public class AutomaticallyCuratePackageCommandFacts
+ {
+ public class TheExecuteMethod
+ {
+ [Fact]
+ public void WillCuratePackageUsingAllPackageCurators()
+ {
+ var cmd = new TestableAutomaticallyCuratePackageCommand();
+ var firstStubCurator = new Mock<IAutomaticPackageCurator>();
+ var secondStubCurator = new Mock<IAutomaticPackageCurator>();
+ cmd.StubCurators.Add(firstStubCurator);
+ cmd.StubCurators.Add(secondStubCurator);
+
+ cmd.Execute(new Package(), new Mock<IPackage>().Object);
+
+ firstStubCurator.Verify(stub => stub.Curate(It.IsAny<Package>(), It.IsAny<IPackage>()));
+ secondStubCurator.Verify(stub => stub.Curate(It.IsAny<Package>(), It.IsAny<IPackage>()));
+ }
+ }
+
+ public class TestableAutomaticallyCuratePackageCommand : AutomaticallyCuratePackageCommand
+ {
+ public TestableAutomaticallyCuratePackageCommand()
+ : base(null)
+ {
+ StubCurators = new List<Mock<IAutomaticPackageCurator>>();
+ }
+
+ public List<Mock<IAutomaticPackageCurator>> StubCurators { get; private set; }
+
+ protected override IEnumerable<T> GetServices<T>()
+ {
+ if (typeof(T) == typeof(IAutomaticPackageCurator))
+ return StubCurators.Select(stub => (T)stub.Object);
+
+ throw new Exception("Tried to get unexpected servicves");
+ }
+ }
+ }
+}
+
View
37 Facts/Controllers/PackagesControllerFacts.cs
@@ -1040,6 +1040,35 @@ public void WillRedirectToPackagePage()
Assert.Equal(RouteName.DisplayPackage, result.RouteName);
fakeFileStream.Dispose();
}
+
+ [Fact]
+ public void WillCurateThePackage()
+ {
+ var fakeCurrentUser = new User { Key = 42 };
+ var fakeUserSvc = new Mock<IUserService>();
+ fakeUserSvc.Setup(x => x.FindByUsername(It.IsAny<string>())).Returns(fakeCurrentUser);
+ var fakeIdentity = new Mock<IIdentity>();
+ fakeIdentity.Setup(x => x.Name).Returns("theUsername");
+ var fakeUploadFileSvc = new Mock<IUploadFileService>();
+ var fakeFileStream = new MemoryStream();
+ fakeUploadFileSvc.Setup(x => x.GetUploadFile(42)).Returns(fakeFileStream);
+ var fakePackageSvc = new Mock<IPackageService>();
+ var fakePackage = new Package { PackageRegistration = new PackageRegistration { Id = "theId" }, Version = "theVersion" };
+ fakePackageSvc.Setup(x => x.CreatePackage(It.IsAny<IPackage>(), It.IsAny<User>())).Returns(fakePackage);
+ var fakeNuGetPackage = new Mock<IPackage>();
+ var fakeAutoCuratePackageCmd = new Mock<IAutomaticallyCuratePackageCommand>();
+ var controller = CreateController(
+ packageSvc: fakePackageSvc,
+ uploadFileSvc: fakeUploadFileSvc,
+ userSvc: fakeUserSvc,
+ fakeIdentity: fakeIdentity,
+ fakeNuGetPackage: fakeNuGetPackage,
+ autoCuratePackageCmd: fakeAutoCuratePackageCmd);
+
+ controller.VerifyPackage(false);
+
+ fakeAutoCuratePackageCmd.Verify(fake => fake.Execute(fakePackage, fakeNuGetPackage.Object));
+ }
}
public class TheCancelVerifyPackageAction
@@ -1094,22 +1123,24 @@ public void RedirectsToUploadPageAfterDelete()
Mock<IIdentity> fakeIdentity = null,
Mock<IPackage> fakeNuGetPackage = null,
Mock<ISearchService> searchService = null,
- Exception readPackageException = null)
+ Exception readPackageException = null,
+ Mock<IAutomaticallyCuratePackageCommand> autoCuratePackageCmd = null)
{
packageSvc = packageSvc ?? new Mock<IPackageService>();
uploadFileSvc = uploadFileSvc ?? new Mock<IUploadFileService>();
userSvc = userSvc ?? new Mock<IUserService>();
messageSvc = messageSvc ?? new Mock<IMessageService>();
searchService = searchService ?? CreateSearchService();
-
+ autoCuratePackageCmd = autoCuratePackageCmd ?? new Mock<IAutomaticallyCuratePackageCommand>();
var controller = new Mock<PackagesController>(
packageSvc.Object,
uploadFileSvc.Object,
userSvc.Object,
messageSvc.Object,
- searchService.Object);
+ searchService.Object,
+ autoCuratePackageCmd.Object);
controller.CallBase = true;
if (httpContext != null)
View
2 Facts/Facts.csproj
@@ -91,6 +91,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
+ <Compile Include="Commands\AutomaticallyCuratePackageCommandFacts.cs" />
<Compile Include="Commands\CreatedCuratedPackageCommandFacts.cs" />
<Compile Include="Controllers\AuthenticationControllerFacts.cs" />
<Compile Include="Controllers\ApiControllerFacts.cs" />
@@ -103,6 +104,7 @@
<Compile Include="Infrastructure\CookieTempDataProviderFacts.cs" />
<Compile Include="Infrastructure\Jobs\UpdateStatisticsJobFacts.cs" />
<Compile Include="Infrastructure\LuceneIndexingServiceFacts.cs" />
+ <Compile Include="PackageCurators\WebMatrixPackageCuratorFacts.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RequireRemoteHttpsAttributeFacts.cs" />
<Compile Include="Routing\VersionRouteConstraintFacts.cs" />
View
244 Facts/PackageCurators/WebMatrixPackageCuratorFacts.cs
@@ -0,0 +1,244 @@
+using System;
+using Moq;
+using NuGet;
+using Xunit;
+
+namespace NuGetGallery.PackageCurators
+{
+ public class WebMatrixPackageCuratorFacts
+ {
+ public class TheCurateMethod
+ {
+ [Fact]
+ public void WillNotIncludeThePackageWhenTheWebMatrixCuratedFeedDoesNotExist()
+ {
+ var curator = new TestableWebMatrixPackageCurator();
+ curator.StubCuratedFeedByNameQry.Setup(stub => stub.Execute(It.IsAny<string>(), It.IsAny<bool>())).Returns((CuratedFeed)null);
+
+ curator.Curate(CreateStubGalleryPackage(), null);
+
+ curator.StubCreatedCuratedPackageCmd.Verify(stub => stub.Execute(
+ It.IsAny<int>(),
+ It.IsAny<int>(),
+ It.IsAny<bool>(),
+ It.IsAny<bool>(),
+ It.IsAny<string>()), Times.Never());
+ }
+
+ [Fact]
+ public void WillNotIncludeThePackageWhenItIsNotTheLatestStable()
+ {
+ var curator = new TestableWebMatrixPackageCurator();
+ var stubGalleryPackage = CreateStubGalleryPackage();
+ stubGalleryPackage.IsLatestStable = false;
+
+ curator.Curate(stubGalleryPackage, null);
+
+ curator.StubCreatedCuratedPackageCmd.Verify(stub => stub.Execute(
+ It.IsAny<int>(),
+ It.IsAny<int>(),
+ It.IsAny<bool>(),
+ It.IsAny<bool>(),
+ It.IsAny<string>()), Times.Never());
+ }
+
+ [Fact]
+ public void WillIncludeThePackageWhenItIsTaggedWithAspNetWebPages()
+ {
+ var curator = new TestableWebMatrixPackageCurator();
+ var stubGalleryPackage = CreateStubGalleryPackage();
+ stubGalleryPackage.Tags = "aTag aspnetwebpages aThirdTag";
+
+ curator.Curate(stubGalleryPackage, null);
+
+ curator.StubCreatedCuratedPackageCmd.Verify(stub => stub.Execute(
+ It.IsAny<int>(),
+ It.IsAny<int>(),
+ It.IsAny<bool>(),
+ It.IsAny<bool>(),
+ It.IsAny<string>()), Times.Once());
+ }
+
+ [Fact]
+ public void WillNotExamineTheNuGetPackageFilesWhenTaggedWithAspNetWebPages()
+ {
+ var curator = new TestableWebMatrixPackageCurator();
+ var stubGalleryPackage = CreateStubGalleryPackage();
+ stubGalleryPackage.Tags = "aTag aspnetwebpages aThirdTag";
+ var stubNuGetPackage = CreateStubNuGetPackage();
+
+ curator.Curate(stubGalleryPackage, stubNuGetPackage.Object);
+
+ stubNuGetPackage.Verify(stub => stub.GetFiles(), Times.Never());
+ }
+
+ [Fact]
+ public void WillNotIncludeThePackageWhenNotTaggedAndThereIsAPowerShellFile()
+ {
+ var curator = new TestableWebMatrixPackageCurator();
+ var stubNuGetPackage = CreateStubNuGetPackage();
+ stubNuGetPackage.Setup(stub => stub.GetFiles()).Returns(new[]
+ {
+ CreateStubNuGetPackageFile("foo.txt").Object,
+ CreateStubNuGetPackageFile("foo.ps1").Object,
+ CreateStubNuGetPackageFile("foo.cs").Object
+ });
+
+ curator.Curate(CreateStubGalleryPackage(), stubNuGetPackage.Object);
+
+ curator.StubCreatedCuratedPackageCmd.Verify(stub => stub.Execute(
+ It.IsAny<int>(),
+ It.IsAny<int>(),
+ It.IsAny<bool>(),
+ It.IsAny<bool>(),
+ It.IsAny<string>()), Times.Never());
+ }
+
+ [Fact]
+ public void WillNotIncludeThePackageWhenNotTaggedAndThereIsT4Template()
+ {
+ var curator = new TestableWebMatrixPackageCurator();
+ var stubNuGetPackage = CreateStubNuGetPackage();
+ stubNuGetPackage.Setup(stub => stub.GetFiles()).Returns(new[]
+ {
+ CreateStubNuGetPackageFile("foo.txt").Object,
+ CreateStubNuGetPackageFile("foo.t4").Object,
+ CreateStubNuGetPackageFile("foo.cs").Object
+ });
+
+ curator.Curate(CreateStubGalleryPackage(), stubNuGetPackage.Object);
+
+ curator.StubCreatedCuratedPackageCmd.Verify(stub => stub.Execute(
+ It.IsAny<int>(),
+ It.IsAny<int>(),
+ It.IsAny<bool>(),
+ It.IsAny<bool>(),
+ It.IsAny<string>()), Times.Never());
+ }
+
+ [Fact]
+ public void WillIncludeThePackageWhenThereIsNotPowerShellOrT4File()
+ {
+ var curator = new TestableWebMatrixPackageCurator();
+ var stubNuGetPackage = CreateStubNuGetPackage();
+ stubNuGetPackage.Setup(stub => stub.GetFiles()).Returns(new[]
+ {
+ CreateStubNuGetPackageFile("foo.txt").Object,
+ CreateStubNuGetPackageFile("foo.cs").Object
+ });
+
+ curator.Curate(CreateStubGalleryPackage(), stubNuGetPackage.Object);
+
+ curator.StubCreatedCuratedPackageCmd.Verify(stub => stub.Execute(
+ It.IsAny<int>(),
+ It.IsAny<int>(),
+ It.IsAny<bool>(),
+ It.IsAny<bool>(),
+ It.IsAny<string>()), Times.Once());
+ }
+
+ [Fact]
+ public void WillIncludeThePackageUsingTheCuratedFeedKey()
+ {
+ var curator = new TestableWebMatrixPackageCurator();
+ curator.StubCuratedFeed.Key = 42;
+
+ curator.Curate(CreateStubGalleryPackage(), CreateStubNuGetPackage().Object);
+
+ curator.StubCreatedCuratedPackageCmd.Verify(stub => stub.Execute(
+ 42,
+ It.IsAny<int>(),
+ It.IsAny<bool>(),
+ It.IsAny<bool>(),
+ It.IsAny<string>()));
+ }
+
+ [Fact]
+ public void WillIncludeThePackageUsingThePackageRegistrationKey()
+ {
+ var curator = new TestableWebMatrixPackageCurator();
+ var stubGalleryPackage = CreateStubGalleryPackage();
+ stubGalleryPackage.PackageRegistration.Key = 42;
+
+ curator.Curate(stubGalleryPackage, CreateStubNuGetPackage().Object);
+
+ curator.StubCreatedCuratedPackageCmd.Verify(stub => stub.Execute(
+ It.IsAny<int>(),
+ 42,
+ It.IsAny<bool>(),
+ It.IsAny<bool>(),
+ It.IsAny<string>()));
+ }
+
+ [Fact]
+ public void WillSetTheAutomaticBitWhenIncludingThePackage()
+ {
+ var curator = new TestableWebMatrixPackageCurator();
+
+ curator.Curate(CreateStubGalleryPackage(), CreateStubNuGetPackage().Object);
+
+ curator.StubCreatedCuratedPackageCmd.Verify(stub => stub.Execute(
+ It.IsAny<int>(),
+ It.IsAny<int>(),
+ It.IsAny<bool>(),
+ true,
+ It.IsAny<string>()));
+ }
+
+ static Package CreateStubGalleryPackage()
+ {
+ return new Package
+ {
+ IsLatestStable = true ,
+ PackageRegistration = new PackageRegistration
+ {
+ Key = 0,
+ },
+ };
+ }
+
+ static Mock<IPackage> CreateStubNuGetPackage()
+ {
+ var stubNuGetPackage = new Mock<IPackage>();
+ stubNuGetPackage.Setup(stub => stub.GetFiles()).Returns(new IPackageFile[] {});
+ return stubNuGetPackage;
+ }
+
+ static Mock<IPackageFile> CreateStubNuGetPackageFile(string path)
+ {
+ var stubPackageFile = new Mock<IPackageFile>();
+ stubPackageFile.Setup(stub => stub.Path).Returns(path);
+ return stubPackageFile;
+ }
+ }
+
+ public class TestableWebMatrixPackageCurator : WebMatrixPackageCurator
+ {
+ public TestableWebMatrixPackageCurator()
+ {
+ StubCreatedCuratedPackageCmd = new Mock<ICreatedCuratedPackageCommand>();
+ StubCuratedFeed = new CuratedFeed { Key = 0 };
+ StubCuratedFeedByNameQry = new Mock<ICuratedFeedByNameQuery>();
+
+ StubCuratedFeedByNameQry
+ .Setup(stub => stub.Execute(It.IsAny<string>(), It.IsAny<bool>()))
+ .Returns(StubCuratedFeed);
+ }
+
+ public Mock<ICreatedCuratedPackageCommand> StubCreatedCuratedPackageCmd { get; set; }
+ public CuratedFeed StubCuratedFeed { get; private set; }
+ public Mock<ICuratedFeedByNameQuery> StubCuratedFeedByNameQry { get; private set; }
+
+ protected override T GetService<T>()
+ {
+ if (typeof(T) == typeof(ICreatedCuratedPackageCommand))
+ return (T)StubCreatedCuratedPackageCmd.Object;
+
+ if (typeof(T) == typeof(ICuratedFeedByNameQuery))
+ return (T)StubCuratedFeedByNameQry.Object;
+
+ throw new Exception("Tried to get an unexpected service.");
+ }
+ }
+ }
+}
View
7 Website/App_Start/ContainerBindings.cs
@@ -165,7 +165,14 @@ public override void Load()
Bind<IUploadFileService>()
.To<UploadFileService>();
+ // todo: bind all package curators by convention
+ Bind<IAutomaticPackageCurator>()
+ .To<WebMatrixPackageCurator>();
+
// todo: bind all commands by convention
+ Bind<IAutomaticallyCuratePackageCommand>()
+ .To<AutomaticallyCuratePackageCommand>()
+ .InRequestScope();
Bind<ICreatedCuratedPackageCommand>()
.To<CreatedCuratedPackageCommand>()
.InRequestScope();
View
8 Website/Commands/AppCommand.cs
@@ -1,4 +1,5 @@
-using System.Web.Mvc;
+using System.Collections.Generic;
+using System.Web.Mvc;
namespace NuGetGallery
{
@@ -15,5 +16,10 @@ protected virtual T GetService<T>()
{
return DependencyResolver.Current.GetService<T>();
}
+
+ protected virtual IEnumerable<T> GetServices<T>()
+ {
+ return DependencyResolver.Current.GetServices<T>();
+ }
}
}
View
31 Website/Commands/AutomaticallyCuratePackageCommand.cs
@@ -0,0 +1,31 @@
+using NuGet;
+
+namespace NuGetGallery
+{
+ public interface IAutomaticallyCuratePackageCommand
+ {
+ void Execute(
+ Package galleryPackage,
+ IPackage nugetPackage);
+ }
+
+ public class AutomaticallyCuratePackageCommand : AppCommand, IAutomaticallyCuratePackageCommand
+ {
+ public AutomaticallyCuratePackageCommand(IEntitiesContext entities)
+ : base(entities)
+ {
+ }
+
+ public void Execute(
+ Package galleryPackage,
+ IPackage nugetPackage)
+ {
+ foreach(var curator in GetServices<IAutomaticPackageCurator>())
+ {
+ curator.Curate(
+ galleryPackage,
+ nugetPackage);
+ }
+ }
+ }
+}
View
1,076 Website/Controllers/PackagesController.cs
@@ -1,536 +1,540 @@
-using System;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Net.Mail;
-using System.Security.Principal;
-using System.Transactions;
-using System.Web;
-using System.Web.Mvc;
-using NuGet;
-using PoliteCaptcha;
-
-namespace NuGetGallery
-{
- public partial class PackagesController : Controller
- {
- // TODO: add support for URL-based package submission
- // TODO: add support for uploading logos and screenshots
- // TODO: improve validation summary emphasis
-
- private readonly IPackageService packageSvc;
- private readonly IUploadFileService uploadFileSvc;
- private readonly IUserService userSvc;
- private readonly IMessageService messageService;
- private readonly ISearchService searchSvc;
-
- public PackagesController(
- IPackageService packageSvc,
- IUploadFileService uploadFileSvc,
- IUserService userSvc,
- IMessageService messageService,
- ISearchService searchSvc)
- {
- this.packageSvc = packageSvc;
- this.uploadFileSvc = uploadFileSvc;
- this.userSvc = userSvc;
- this.messageService = messageService;
- this.searchSvc = searchSvc;
- }
-
- [Authorize]
- public virtual ActionResult UploadPackage()
- {
- var currentUser = userSvc.FindByUsername(GetIdentity().Name);
-
- using (var existingUploadFile = uploadFileSvc.GetUploadFile(currentUser.Key))
- {
- if (existingUploadFile != null)
- return RedirectToRoute(RouteName.VerifyPackage);
- }
-
- return View();
- }
-
- [Authorize, HttpPost, ValidateAntiForgeryToken]
- public virtual ActionResult UploadPackage(HttpPostedFileBase uploadFile)
- {
- var currentUser = userSvc.FindByUsername(GetIdentity().Name);
-
- using (var existingUploadFile = uploadFileSvc.GetUploadFile(currentUser.Key))
- {
- if (existingUploadFile != null)
- return new HttpStatusCodeResult(409, "Cannot upload file because an upload is already in progress.");
- }
-
- if (uploadFile == null)
- {
- ModelState.AddModelError(String.Empty, Strings.UploadFileIsRequired);
- return View();
- }
-
- if (!Path.GetExtension(uploadFile.FileName).Equals(Constants.NuGetPackageFileExtension, StringComparison.OrdinalIgnoreCase))
- {
- ModelState.AddModelError(String.Empty, Strings.UploadFileMustBeNuGetPackage);
- return View();
- }
-
- IPackage nuGetPackage;
- try
- {
- using (var uploadStream = uploadFile.InputStream)
- {
- nuGetPackage = ReadNuGetPackage(uploadStream);
- }
- }
- catch
- {
- ModelState.AddModelError(String.Empty, Strings.FailedToReadUploadFile);
- return View();
- }
-
- var packageRegistration = packageSvc.FindPackageRegistrationById(nuGetPackage.Id);
- if (packageRegistration != null && !packageRegistration.Owners.AnySafe(x => x.Key == currentUser.Key))
- {
- ModelState.AddModelError(String.Empty, String.Format(CultureInfo.CurrentCulture, Strings.PackageIdNotAvailable, packageRegistration.Id));
- return View();
- }
-
- var package = packageSvc.FindPackageByIdAndVersion(nuGetPackage.Id, nuGetPackage.Version.ToStringSafe());
- if (package != null)
- {
- ModelState.AddModelError(String.Empty, String.Format(CultureInfo.CurrentCulture, Strings.PackageExistsAndCannotBeModified, package.PackageRegistration.Id, package.Version));
- return View();
- }
-
- using (var fileStream = nuGetPackage.GetStream())
- {
- uploadFileSvc.SaveUploadFile(currentUser.Key, fileStream);
- }
-
- return RedirectToRoute(RouteName.VerifyPackage);
- }
-
- public virtual ActionResult DisplayPackage(string id, string version)
- {
- var package = packageSvc.FindPackageByIdAndVersion(id, version);
-
- if (package == null)
- {
- return PackageNotFound(id, version);
- }
- var model = new DisplayPackageViewModel(package);
- return View(model);
- }
-
- public virtual ActionResult ListPackages(string q, string sortOrder = Constants.PopularitySortOrder, int page = 1)
- {
- if (page < 1)
- {
- page = 1;
- }
-
- IQueryable<Package> packageVersions = packageSvc.GetLatestPackageVersions(allowPrerelease: true);
-
- q = (q ?? "").Trim();
-
- if (GetIdentity().IsAuthenticated)
- {
- // Only show listed packages. For unlisted packages, only show them if the owner is viewing it.
- packageVersions = packageVersions.Where(p => p.Listed || p.PackageRegistration.Owners.Any(owner => owner.Username == User.Identity.Name));
- }
- else
- {
- packageVersions = packageVersions.Where(p => p.Listed);
- }
-
- int totalHits;
- if (!String.IsNullOrEmpty(q))
- {
- if (sortOrder.Equals(Constants.RelevanceSortOrder, StringComparison.OrdinalIgnoreCase))
- {
- packageVersions = searchSvc.SearchWithRelevance(packageVersions, q, take: page * Constants.DefaultPackageListPageSize, totalHits: out totalHits);
- if (page == 1 && !packageVersions.Any())
- {
- // In the event the index wasn't updated, we may get an incorrect count.
- totalHits = 0;
- }
- }
- else
- {
- packageVersions = searchSvc.Search(packageVersions, q)
- .SortBy(GetSortExpression(sortOrder));
- totalHits = packageVersions.Count();
- }
- }
- else
- {
- packageVersions = packageVersions.SortBy(GetSortExpression(sortOrder));
- totalHits = packageVersions.Count();
- }
-
- var viewModel = new PackageListViewModel(packageVersions,
- q,
- sortOrder,
- totalHits,
- page - 1,
- Constants.DefaultPackageListPageSize,
- Url);
-
- ViewBag.SearchTerm = q;
-
- return View(viewModel);
- }
-
- private static string GetSortExpression(string sortOrder)
- {
- switch (sortOrder)
- {
- case Constants.AlphabeticSortOrder:
- return "PackageRegistration.Id";
- case Constants.RecentSortOrder:
- return "Published desc";
- case Constants.PopularitySortOrder:
- default:
- return "PackageRegistration.DownloadCount desc";
- }
- }
-
- // NOTE: Intentionally NOT requiring authentication
- public virtual ActionResult ReportAbuse(string id, string version)
- {
- var package = packageSvc.FindPackageByIdAndVersion(id, version);
-
- if (package == null)
- {
- return PackageNotFound(id, version);
- }
-
- var model = new ReportAbuseViewModel
- {
- PackageId = id,
- PackageVersion = package.Version,
- };
-
- if (Request.IsAuthenticated)
- {
- var user = userSvc.FindByUsername(HttpContext.User.Identity.Name);
- if (user.Confirmed)
- {
- model.ConfirmedUser = true;
- }
- }
-
- return View(model);
- }
-
- [HttpPost, ValidateAntiForgeryToken, ValidateSpamPrevention]
- public virtual ActionResult ReportAbuse(string id, string version, ReportAbuseViewModel reportForm)
- {
- if (!ModelState.IsValid)
- {
- return ReportAbuse(id, version);
- }
-
- var package = packageSvc.FindPackageByIdAndVersion(id, version);
- if (package == null)
- {
- return PackageNotFound(id, version);
- }
-
- MailAddress from = null;
- if (Request.IsAuthenticated)
- {
- var user = userSvc.FindByUsername(HttpContext.User.Identity.Name);
- from = user.ToMailAddress();
- }
- else
- {
- from = new MailAddress(reportForm.Email);
- }
-
- messageService.ReportAbuse(from, package, reportForm.Message);
-
- TempData["Message"] = "Your abuse report has been sent to the gallery operators.";
- return RedirectToAction(MVC.Packages.DisplayPackage(id, version));
- }
-
- [Authorize]
- public virtual ActionResult ContactOwners(string id)
- {
- var package = packageSvc.FindPackageRegistrationById(id);
-
- if (package == null)
- {
- return PackageNotFound(id);
- }
-
- var model = new ContactOwnersViewModel
- {
- PackageId = package.Id,
- Owners = package.Owners.Where(u => u.EmailAllowed)
- };
-
- return View(model);
- }
-
- [HttpPost, Authorize, ValidateAntiForgeryToken]
- public virtual ActionResult ContactOwners(string id, ContactOwnersViewModel contactForm)
- {
- if (!ModelState.IsValid)
- {
- return ContactOwners(id);
- }
-
- var package = packageSvc.FindPackageRegistrationById(id);
- if (package == null)
- {
- return PackageNotFound(id);
- }
-
- var user = userSvc.FindByUsername(HttpContext.User.Identity.Name);
- var fromAddress = new MailAddress(user.EmailAddress, user.Username);
- messageService.SendContactOwnersMessage(fromAddress, package, contactForm.Message, Url.Action(MVC.Users.Edit(), protocol: Request.Url.Scheme));
-
- string message = String.Format(CultureInfo.CurrentCulture, "Your message has been sent to the owners of {0}.", id);
- TempData["Message"] = message;
- return RedirectToAction(MVC.Packages.DisplayPackage(id, null));
- }
-
- // This is the page that explains why there's no download link.
- public virtual ActionResult Download()
- {
- return View();
- }
-
- [Authorize]
- public virtual ActionResult ManagePackageOwners(string id, string version)
- {
- var package = packageSvc.FindPackageByIdAndVersion(id, version);
- if (package == null)
- {
- return PackageNotFound(id, version);
- }
- if (!package.IsOwner(HttpContext.User))
- {
- return new HttpStatusCodeResult(401, "Unauthorized");
- }
-
- var model = new ManagePackageOwnersViewModel(package, HttpContext.User);
-
- return View(model);
- }
-
- [Authorize]
- public virtual ActionResult Delete(string id, string version)
- {
- return GetPackageOwnerActionFormResult(id, version);
- }
-
- [Authorize, HttpPost, ValidateAntiForgeryToken]
- public virtual ActionResult Delete(string id, string version, bool? listed)
- {
- return Delete(id, version, listed, Url.Package);
- }
-
- internal virtual ActionResult Delete(string id, string version, bool? listed, Func<Package, string> urlFactory)
- {
- var package = packageSvc.FindPackageByIdAndVersion(id, version);
- if (package == null)
- {
- return PackageNotFound(id, version);
- }
- if (!package.IsOwner(HttpContext.User))
- {
- return new HttpStatusCodeResult(401, "Unauthorized");
- }
-
- if (!(listed ?? false))
- {
- packageSvc.MarkPackageUnlisted(package);
- }
- else
- {
- packageSvc.MarkPackageListed(package);
- }
-
- return Redirect(urlFactory(package));
- }
-
- [Authorize]
- public virtual ActionResult Edit(string id, string version)
- {
- return GetPackageOwnerActionFormResult(id, version);
- }
-
- [Authorize, HttpPost, ValidateAntiForgeryToken]
- public virtual ActionResult Edit(string id, string version, bool? listed)
- {
- return Edit(id, version, listed, Url.Package);
- }
-
- [Authorize]
- public virtual ActionResult ConfirmOwner(string id, string username, string token)
- {
- if (String.IsNullOrEmpty(token))
- {
- return HttpNotFound();
- }
-
- var package = packageSvc.FindPackageRegistrationById(id);
- if (package == null)
- {
- return HttpNotFound();
- }
-
- var user = userSvc.FindByUsername(username);
- if (user == null)
- {
- return HttpNotFound();
- }
-
- if (!String.Equals(user.Username, User.Identity.Name, StringComparison.OrdinalIgnoreCase))
- {
- return new HttpStatusCodeResult(403);
- }
-
- var model = new PackageOwnerConfirmationModel
- {
- Success = packageSvc.ConfirmPackageOwner(package, user, token),
- PackageId = id
- };
-
- return View(model);
- }
-
- internal virtual ActionResult Edit(string id, string version, bool? listed, Func<Package, string> urlFactory)
- {
- var package = packageSvc.FindPackageByIdAndVersion(id, version);
- if (package == null)
- {
- return PackageNotFound(id, version);
- }
- if (!package.IsOwner(HttpContext.User))
- {
- return new HttpStatusCodeResult(401, "Unauthorized");
- }
-
- if (!(listed ?? false))
- {
- packageSvc.MarkPackageUnlisted(package);
- }
- else
- {
- packageSvc.MarkPackageListed(package);
- }
- return Redirect(urlFactory(package));
- }
-
- private ActionResult GetPackageOwnerActionFormResult(string id, string version)
- {
- var package = packageSvc.FindPackageByIdAndVersion(id, version);
- if (package == null)
- {
- return PackageNotFound(id, version);
- }
- if (!package.IsOwner(HttpContext.User))
- {
- return new HttpStatusCodeResult(401, "Unauthorized");
- }
-
- var model = new DisplayPackageViewModel(package);
- return View(model);
- }
-
- // We may want to have a specific behavior for package not found
- private ActionResult PackageNotFound(string id)
- {
- return PackageNotFound(id, null);
- }
-
- private ActionResult PackageNotFound(string id, string version)
- {
- return HttpNotFound();
- }
-
- [Authorize]
- public virtual ActionResult VerifyPackage()
- {
- var currentUser = userSvc.FindByUsername(GetIdentity().Name);
-
- IPackage package;
- using (var uploadFile = uploadFileSvc.GetUploadFile(currentUser.Key))
- {
- if (uploadFile == null)
- return RedirectToRoute(RouteName.UploadPackage);
-
- package = ReadNuGetPackage(uploadFile);
- }
-
- return View(new VerifyPackageViewModel
- {
- Id = package.Id,
- Version = package.Version.ToStringSafe(),
- Title = package.Title,
- Summary = package.Summary,
- Description = package.Description,
- RequiresLicenseAcceptance = package.RequireLicenseAcceptance,
- LicenseUrl = package.LicenseUrl.ToStringSafe(),
- Tags = package.Tags,
- ProjectUrl = package.ProjectUrl.ToStringSafe(),
- Authors = package.Authors.Flatten(),
- Listed = package.Listed
- });
- }
-
- [Authorize, HttpPost, ValidateAntiForgeryToken]
- public virtual ActionResult VerifyPackage(bool? listed)
- {
- var currentUser = userSvc.FindByUsername(GetIdentity().Name);
-
- IPackage nugetPackage;
- using (var uploadFile = uploadFileSvc.GetUploadFile(currentUser.Key))
- {
- if (uploadFile == null)
- return HttpNotFound();
-
- nugetPackage = ReadNuGetPackage(uploadFile);
- }
-
- Package package;
- using (var tx = new TransactionScope())
- {
- package = packageSvc.CreatePackage(nugetPackage, currentUser);
- packageSvc.PublishPackage(package.PackageRegistration.Id, package.Version);
- if (listed.HasValue && listed.Value == false)
- packageSvc.MarkPackageUnlisted(package);
- uploadFileSvc.DeleteUploadFile(currentUser.Key);
- tx.Complete();
- }
-
- TempData["Message"] = String.Format(CultureInfo.CurrentCulture, Strings.SuccessfullyUploadedPackage, package.PackageRegistration.Id, package.Version);
- return RedirectToRoute(RouteName.DisplayPackage, new { package.PackageRegistration.Id, package.Version });
- }
-
- [Authorize, HttpPost, ValidateAntiForgeryToken]
- public virtual ActionResult CancelUpload()
- {
- var currentUser = userSvc.FindByUsername(GetIdentity().Name);
- uploadFileSvc.DeleteUploadFile(currentUser.Key);
-
- return RedirectToAction(MVC.Packages.UploadPackage());
- }
-
- // this methods exist to make unit testing easier
- protected internal virtual IIdentity GetIdentity()
- {
- return User.Identity;
- }
-
- // this methods exist to make unit testing easier
- protected internal virtual IPackage ReadNuGetPackage(Stream stream)
- {
- return new ZipPackage(stream);
- }
- }
-}
+using System;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Net.Mail;
+using System.Security.Principal;
+using System.Transactions;
+using System.Web;
+using System.Web.Mvc;
+using NuGet;
+using PoliteCaptcha;
+
+namespace NuGetGallery
+{
+ public partial class PackagesController : Controller
+ {
+ // TODO: add support for URL-based package submission
+ // TODO: add support for uploading logos and screenshots
+ // TODO: improve validation summary emphasis
+
+ private readonly IPackageService packageSvc;
+ private readonly IUploadFileService uploadFileSvc;
+ private readonly IUserService userSvc;
+ private readonly IMessageService messageService;
+ private readonly ISearchService searchSvc;
+ private readonly IAutomaticallyCuratePackageCommand autoCuratedPackageCmd;
+
+ public PackagesController(
+ IPackageService packageSvc,
+ IUploadFileService uploadFileSvc,
+ IUserService userSvc,
+ IMessageService messageService,
+ ISearchService searchSvc,
+ IAutomaticallyCuratePackageCommand autoCuratedPackageCmd)
+ {
+ this.packageSvc = packageSvc;
+ this.uploadFileSvc = uploadFileSvc;
+ this.userSvc = userSvc;
+ this.messageService = messageService;
+ this.searchSvc = searchSvc;
+ this.autoCuratedPackageCmd = autoCuratedPackageCmd;
+ }
+
+ [Authorize]
+ public virtual ActionResult UploadPackage()
+ {
+ var currentUser = userSvc.FindByUsername(GetIdentity().Name);
+
+ using (var existingUploadFile = uploadFileSvc.GetUploadFile(currentUser.Key))
+ {
+ if (existingUploadFile != null)
+ return RedirectToRoute(RouteName.VerifyPackage);
+ }
+
+ return View();
+ }
+
+ [Authorize, HttpPost, ValidateAntiForgeryToken]
+ public virtual ActionResult UploadPackage(HttpPostedFileBase uploadFile)
+ {
+ var currentUser = userSvc.FindByUsername(GetIdentity().Name);
+
+ using (var existingUploadFile = uploadFileSvc.GetUploadFile(currentUser.Key))
+ {
+ if (existingUploadFile != null)
+ return new HttpStatusCodeResult(409, "Cannot upload file because an upload is already in progress.");
+ }
+
+ if (uploadFile == null)
+ {
+ ModelState.AddModelError(String.Empty, Strings.UploadFileIsRequired);
+ return View();
+ }
+
+ if (!Path.GetExtension(uploadFile.FileName).Equals(Constants.NuGetPackageFileExtension, StringComparison.OrdinalIgnoreCase))
+ {
+ ModelState.AddModelError(String.Empty, Strings.UploadFileMustBeNuGetPackage);
+ return View();
+ }
+
+ IPackage nuGetPackage;
+ try
+ {
+ using (var uploadStream = uploadFile.InputStream)
+ {
+ nuGetPackage = ReadNuGetPackage(uploadStream);
+ }
+ }
+ catch
+ {
+ ModelState.AddModelError(String.Empty, Strings.FailedToReadUploadFile);
+ return View();
+ }
+
+ var packageRegistration = packageSvc.FindPackageRegistrationById(nuGetPackage.Id);
+ if (packageRegistration != null && !packageRegistration.Owners.AnySafe(x => x.Key == currentUser.Key))
+ {
+ ModelState.AddModelError(String.Empty, String.Format(CultureInfo.CurrentCulture, Strings.PackageIdNotAvailable, packageRegistration.Id));
+ return View();
+ }
+
+ var package = packageSvc.FindPackageByIdAndVersion(nuGetPackage.Id, nuGetPackage.Version.ToStringSafe());
+ if (package != null)
+ {
+ ModelState.AddModelError(String.Empty, String.Format(CultureInfo.CurrentCulture, Strings.PackageExistsAndCannotBeModified, package.PackageRegistration.Id, package.Version));
+ return View();
+ }
+
+ using (var fileStream = nuGetPackage.GetStream())
+ {
+ uploadFileSvc.SaveUploadFile(currentUser.Key, fileStream);
+ }
+
+ return RedirectToRoute(RouteName.VerifyPackage);
+ }
+
+ public virtual ActionResult DisplayPackage(string id, string version)
+ {
+ var package = packageSvc.FindPackageByIdAndVersion(id, version);
+
+ if (package == null)
+ {
+ return PackageNotFound(id, version);
+ }
+ var model = new DisplayPackageViewModel(package);
+ return View(model);
+ }
+
+ public virtual ActionResult ListPackages(string q, string sortOrder = Constants.PopularitySortOrder, int page = 1)
+ {
+ if (page < 1)
+ {
+ page = 1;
+ }
+
+ IQueryable<Package> packageVersions = packageSvc.GetLatestPackageVersions(allowPrerelease: true);
+
+ q = (q ?? "").Trim();
+
+ if (GetIdentity().IsAuthenticated)
+ {
+ // Only show listed packages. For unlisted packages, only show them if the owner is viewing it.
+ packageVersions = packageVersions.Where(p => p.Listed || p.PackageRegistration.Owners.Any(owner => owner.Username == User.Identity.Name));
+ }
+ else
+ {
+ packageVersions = packageVersions.Where(p => p.Listed);
+ }
+
+ int totalHits;
+ if (!String.IsNullOrEmpty(q))
+ {
+ if (sortOrder.Equals(Constants.RelevanceSortOrder, StringComparison.OrdinalIgnoreCase))
+ {
+ packageVersions = searchSvc.SearchWithRelevance(packageVersions, q, take: page * Constants.DefaultPackageListPageSize, totalHits: out totalHits);
+ if (page == 1 && !packageVersions.Any())
+ {
+ // In the event the index wasn't updated, we may get an incorrect count.
+ totalHits = 0;
+ }
+ }
+ else
+ {
+ packageVersions = searchSvc.Search(packageVersions, q)
+ .SortBy(GetSortExpression(sortOrder));
+ totalHits = packageVersions.Count();
+ }
+ }
+ else
+ {
+ packageVersions = packageVersions.SortBy(GetSortExpression(sortOrder));
+ totalHits = packageVersions.Count();
+ }
+
+ var viewModel = new PackageListViewModel(packageVersions,
+ q,
+ sortOrder,
+ totalHits,
+ page - 1,
+ Constants.DefaultPackageListPageSize,
+ Url);
+
+ ViewBag.SearchTerm = q;
+
+ return View(viewModel);
+ }
+
+ private static string GetSortExpression(string sortOrder)
+ {
+ switch (sortOrder)
+ {
+ case Constants.AlphabeticSortOrder:
+ return "PackageRegistration.Id";
+ case Constants.RecentSortOrder:
+ return "Published desc";
+ case Constants.PopularitySortOrder:
+ default:
+ return "PackageRegistration.DownloadCount desc";
+ }
+ }
+
+ // NOTE: Intentionally NOT requiring authentication
+ public virtual ActionResult ReportAbuse(string id, string version)
+ {
+ var package = packageSvc.FindPackageByIdAndVersion(id, version);
+
+ if (package == null)
+ {
+ return PackageNotFound(id, version);
+ }
+
+ var model = new ReportAbuseViewModel
+ {
+ PackageId = id,
+ PackageVersion = package.Version,
+ };
+
+ if (Request.IsAuthenticated)
+ {
+ var user = userSvc.FindByUsername(HttpContext.User.Identity.Name);
+ if (user.Confirmed)
+ {
+ model.ConfirmedUser = true;
+ }
+ }
+
+ return View(model);
+ }
+
+ [HttpPost, ValidateAntiForgeryToken, ValidateSpamPrevention]
+ public virtual ActionResult ReportAbuse(string id, string version, ReportAbuseViewModel reportForm)
+ {
+ if (!ModelState.IsValid)
+ {
+ return ReportAbuse(id, version);
+ }
+
+ var package = packageSvc.FindPackageByIdAndVersion(id, version);
+ if (package == null)
+ {
+ return PackageNotFound(id, version);
+ }
+
+ MailAddress from = null;
+ if (Request.IsAuthenticated)
+ {
+ var user = userSvc.FindByUsername(HttpContext.User.Identity.Name);
+ from = user.ToMailAddress();
+ }
+ else
+ {
+ from = new MailAddress(reportForm.Email);
+ }
+
+ messageService.ReportAbuse(from, package, reportForm.Message);
+
+ TempData["Message"] = "Your abuse report has been sent to the gallery operators.";
+ return RedirectToAction(MVC.Packages.DisplayPackage(id, version));
+ }
+
+ [Authorize]
+ public virtual ActionResult ContactOwners(string id)
+ {
+ var package = packageSvc.FindPackageRegistrationById(id);
+
+ if (package == null)
+ {
+ return PackageNotFound(id);
+ }
+
+ var model = new ContactOwnersViewModel
+ {
+ PackageId = package.Id,
+ Owners = package.Owners.Where(u => u.EmailAllowed)
+ };
+
+ return View(model);
+ }
+
+ [HttpPost, Authorize, ValidateAntiForgeryToken]
+ public virtual ActionResult ContactOwners(string id, ContactOwnersViewModel contactForm)
+ {
+ if (!ModelState.IsValid)
+ {
+ return ContactOwners(id);
+ }
+
+ var package = packageSvc.FindPackageRegistrationById(id);
+ if (package == null)
+ {
+ return PackageNotFound(id);
+ }
+
+ var user = userSvc.FindByUsername(HttpContext.User.Identity.Name);
+ var fromAddress = new MailAddress(user.EmailAddress, user.Username);
+ messageService.SendContactOwnersMessage(fromAddress, package, contactForm.Message, Url.Action(MVC.Users.Edit(), protocol: Request.Url.Scheme));
+
+ string message = String.Format(CultureInfo.CurrentCulture, "Your message has been sent to the owners of {0}.", id);
+ TempData["Message"] = message;
+ return RedirectToAction(MVC.Packages.DisplayPackage(id, null));
+ }
+
+ // This is the page that explains why there's no download link.
+ public virtual ActionResult Download()
+ {
+ return View();
+ }
+
+ [Authorize]
+ public virtual ActionResult ManagePackageOwners(string id, string version)
+ {
+ var package = packageSvc.FindPackageByIdAndVersion(id, version);
+ if (package == null)
+ {
+ return PackageNotFound(id, version);
+ }
+ if (!package.IsOwner(HttpContext.User))
+ {
+ return new HttpStatusCodeResult(401, "Unauthorized");
+ }
+
+ var model = new ManagePackageOwnersViewModel(package, HttpContext.User);
+
+ return View(model);
+ }
+
+ [Authorize]
+ public virtual ActionResult Delete(string id, string version)
+ {
+ return GetPackageOwnerActionFormResult(id, version);
+ }
+
+ [Authorize, HttpPost, ValidateAntiForgeryToken]
+ public virtual ActionResult Delete(string id, string version, bool? listed)
+ {
+ return Delete(id, version, listed, Url.Package);
+ }
+
+ internal virtual ActionResult Delete(string id, string version, bool? listed, Func<Package, string> urlFactory)
+ {
+ var package = packageSvc.FindPackageByIdAndVersion(id, version);
+ if (package == null)
+ {
+ return PackageNotFound(id, version);
+ }
+ if (!package.IsOwner(HttpContext.User))
+ {
+ return new HttpStatusCodeResult(401, "Unauthorized");
+ }
+
+ if (!(listed ?? false))
+ {
+ packageSvc.MarkPackageUnlisted(package);
+ }
+ else
+ {
+ packageSvc.MarkPackageListed(package);
+ }
+
+ return Redirect(urlFactory(package));
+ }
+
+ [Authorize]
+ public virtual ActionResult Edit(string id, string version)
+ {
+ return GetPackageOwnerActionFormResult(id, version);
+ }
+
+ [Authorize, HttpPost, ValidateAntiForgeryToken]
+ public virtual ActionResult Edit(string id, string version, bool? listed)
+ {
+ return Edit(id, version, listed, Url.Package);
+ }
+
+ [Authorize]
+ public virtual ActionResult ConfirmOwner(string id, string username, string token)
+ {
+ if (String.IsNullOrEmpty(token))
+ {
+ return HttpNotFound();
+ }
+
+ var package = packageSvc.FindPackageRegistrationById(id);
+ if (package == null)
+ {
+ return HttpNotFound();
+ }
+
+ var user = userSvc.FindByUsername(username);
+ if (user == null)
+ {
+ return HttpNotFound();
+ }
+
+ if (!String.Equals(user.Username, User.Identity.Name, StringComparison.OrdinalIgnoreCase))
+ {
+ return new HttpStatusCodeResult(403);
+ }
+
+ var model = new PackageOwnerConfirmationModel
+ {
+ Success = packageSvc.ConfirmPackageOwner(package, user, token),
+ PackageId = id
+ };
+
+ return View(model);
+ }
+
+ internal virtual ActionResult Edit(string id, string version, bool? listed, Func<Package, string> urlFactory)
+ {
+ var package = packageSvc.FindPackageByIdAndVersion(id, version);
+ if (package == null)
+ {
+ return PackageNotFound(id, version);
+ }
+ if (!package.IsOwner(HttpContext.User))
+ {
+ return new HttpStatusCodeResult(401, "Unauthorized");
+ }
+
+ if (!(listed ?? false))
+ {
+ packageSvc.MarkPackageUnlisted(package);
+ }
+ else
+ {
+ packageSvc.MarkPackageListed(package);
+ }
+ return Redirect(urlFactory(package));
+ }
+
+ private ActionResult GetPackageOwnerActionFormResult(string id, string version)
+ {
+ var package = packageSvc.FindPackageByIdAndVersion(id, version);
+ if (package == null)
+ {
+ return PackageNotFound(id, version);
+ }
+ if (!package.IsOwner(HttpContext.User))
+ {
+ return new HttpStatusCodeResult(401, "Unauthorized");
+ }
+
+ var model = new DisplayPackageViewModel(package);
+ return View(model);
+ }
+
+ // We may want to have a specific behavior for package not found
+ private ActionResult PackageNotFound(string id)
+ {
+ return PackageNotFound(id, null);
+ }
+
+ private ActionResult PackageNotFound(string id, string version)
+ {
+ return HttpNotFound();
+ }
+
+ [Authorize]
+ public virtual ActionResult VerifyPackage()
+ {
+ var currentUser = userSvc.FindByUsername(GetIdentity().Name);
+
+ IPackage package;
+ using (var uploadFile = uploadFileSvc.GetUploadFile(currentUser.Key))
+ {
+ if (uploadFile == null)
+ return RedirectToRoute(RouteName.UploadPackage);
+
+ package = ReadNuGetPackage(uploadFile);
+ }
+
+ return View(new VerifyPackageViewModel
+ {
+ Id = package.Id,
+ Version = package.Version.ToStringSafe(),
+ Title = package.Title,
+ Summary = package.Summary,
+ Description = package.Description,
+ RequiresLicenseAcceptance = package.RequireLicenseAcceptance,
+ LicenseUrl = package.LicenseUrl.ToStringSafe(),
+ Tags = package.Tags,
+ ProjectUrl = package.ProjectUrl.ToStringSafe(),
+ Authors = package.Authors.Flatten(),
+ Listed = package.Listed
+ });
+ }
+
+ [Authorize, HttpPost, ValidateAntiForgeryToken]
+ public virtual ActionResult VerifyPackage(bool? listed)
+ {
+ var currentUser = userSvc.FindByUsername(GetIdentity().Name);
+
+ IPackage nugetPackage;
+ using (var uploadFile = uploadFileSvc.GetUploadFile(currentUser.Key))
+ {
+ if (uploadFile == null)
+ return HttpNotFound();
+
+ nugetPackage = ReadNuGetPackage(uploadFile);
+ }
+
+ Package package;
+ using (var tx = new TransactionScope())
+ {
+ package = packageSvc.CreatePackage(nugetPackage, currentUser);
+ packageSvc.PublishPackage(package.PackageRegistration.Id, package.Version);
+ if (listed.HasValue && listed.Value == false)
+ packageSvc.MarkPackageUnlisted(package);
+ uploadFileSvc.DeleteUploadFile(currentUser.Key);
+ autoCuratedPackageCmd.Execute(package, nugetPackage);
+ tx.Complete();
+ }
+
+ TempData["Message"] = String.Format(CultureInfo.CurrentCulture, Strings.SuccessfullyUploadedPackage, package.PackageRegistration.Id, package.Version);
+ return RedirectToRoute(RouteName.DisplayPackage, new { package.PackageRegistration.Id, package.Version });
+ }
+
+ [Authorize, HttpPost, ValidateAntiForgeryToken]
+ public virtual ActionResult CancelUpload()
+ {
+ var currentUser = userSvc.FindByUsername(GetIdentity().Name);
+ uploadFileSvc.DeleteUploadFile(currentUser.Key);
+
+ return RedirectToAction(MVC.Packages.UploadPackage());
+ }
+
+ // this methods exist to make unit testing easier
+ protected internal virtual IIdentity GetIdentity()
+ {
+ return User.Identity;
+ }
+
+ // this methods exist to make unit testing easier
+ protected internal virtual IPackage ReadNuGetPackage(Stream stream)
+ {
+ return new ZipPackage(stream);
+ }
+ }
+}
View
17 Website/PackageCurators/AutomaticPackageCurator.cs
@@ -0,0 +1,17 @@
+using System.Web.Mvc;
+using NuGet;
+
+namespace NuGetGallery
+{
+ public abstract class AutomaticPackageCurator : IAutomaticPackageCurator
+ {
+ public abstract void Curate(
+ Package galleryPackage,
+ IPackage nugetPackage);
+
+ protected virtual T GetService<T>()
+ {
+ return DependencyResolver.Current.GetService<T>();
+ }
+ }
+}
View
11 Website/PackageCurators/IAutomaticPackageCurator.cs
@@ -0,0 +1,11 @@
+using NuGet;
+
+namespace NuGetGallery
+{
+ public interface IAutomaticPackageCurator
+ {
+ void Curate(
+ Package galleryPackage,
+ IPackage nugetPackage);
+ }
+}
View
42 Website/PackageCurators/WebMatrixPackageCurator.cs
@@ -0,0 +1,42 @@
+using System.IO;
+using NuGet;
+
+namespace NuGetGallery
+{
+ public class WebMatrixPackageCurator : AutomaticPackageCurator
+ {
+ public override void Curate(
+ Package galleryPackage,
+ IPackage nugetPackage)
+ {
+ var curatedFeed = GetService<ICuratedFeedByNameQuery>().Execute("webmatrix");
+ if (curatedFeed == null)
+ return;
+
+ if (!galleryPackage.IsLatestStable)
+ return;
+
+ var shouldBeIncluded = galleryPackage.Tags != null && galleryPackage.Tags.ToLowerInvariant().Contains("aspnetwebpages");
+
+ if (!shouldBeIncluded)
+ {
+ shouldBeIncluded = true;
+ foreach (var file in nugetPackage.GetFiles())
+ {
+ var fi = new FileInfo(file.Path);
+ if (fi.Extension == ".ps1" || fi.Extension == ".t4")
+ {
+ shouldBeIncluded = false;
+ break;
+ }
+ }
+ }
+
+ if (shouldBeIncluded)
+ GetService<ICreatedCuratedPackageCommand>().Execute(
+ curatedFeed.Key,
+ galleryPackage.PackageRegistration.Key,
+ automaticallyCurated: true);
+ }
+ }
+}
View
2 Website/Services/PackageService.cs
@@ -251,8 +251,6 @@ Package CreatePackageFromNuGetPackage(PackageRegistration packageRegistration, I
if (package != null)
throw new EntityException("A package with identifier '{0}' and version '{1}' already exists.", packageRegistration.Id, package.Version);
- // TODO: add flattened authors, and other properties
- // TODO: add package size
var now = DateTime.UtcNow;
var packageFileStream = nugetPackage.GetStream();
View
4 Website/Website.csproj
@@ -166,6 +166,7 @@
<Compile Include="App_Start\PackageStoreType.cs" />
<Compile Include="Commands\AppCommand.cs" />
<Compile Include="Commands\CreatedCuratedPackageCommand.cs" />
+ <Compile Include="Commands\AutomaticallyCuratePackageCommand.cs" />
<Compile Include="Controllers\AppController.cs" />
<Compile Include="Controllers\CuratedFeedsController.cs" />
<Compile Include="Controllers\CuratedPackagesController.cs" />
@@ -298,6 +299,9 @@
<DependentUpon>201203182132476_CuratedPackages.cs</DependentUpon>
</Compile>
<Compile Include="Migrations\MigrationsConfiguration.cs" />
+ <Compile Include="PackageCurators\IAutomaticPackageCurator.cs" />
+ <Compile Include="PackageCurators\AutomaticPackageCurator.cs" />
+ <Compile Include="PackageCurators\WebMatrixPackageCurator.cs" />
<Compile Include="PackagesController.generated.cs">
<DependentUpon>T4MVC.tt</DependentUpon>
</Compile>

0 comments on commit eb70211

Please sign in to comment.