Permalink
Browse files

Merge pull request #5245 from NuGet/dev

[ReleasePrep][2018.01.18] RI of dev into master
  • Loading branch information...
2 parents 45431c3 + b742b6c commit c60dcbaec322237802b81b3d7abbb59baa0c7042 @loic-sharma loic-sharma committed Jan 9, 2018
Showing with 4,505 additions and 1,473 deletions.
  1. +20 −8 src/NuGetGallery.Core/Auditing/AuditActor.cs
  2. +3 −0 src/NuGetGallery.Core/Entities/Credential.cs
  3. +22 −0 src/NuGetGallery.Core/Entities/EntitiesContext.cs
  4. +26 −0 src/NuGetGallery.Core/Entities/MembershipRequest.cs
  5. +5 −0 src/NuGetGallery.Core/Entities/Organization.cs
  6. +24 −0 src/NuGetGallery.Core/Entities/OrganizationMigrationRequest.cs
  7. +11 −1 src/NuGetGallery.Core/Entities/User.cs
  8. +2 −0 src/NuGetGallery.Core/NuGetGallery.Core.csproj
  9. +43 −10 src/NuGetGallery.Core/Services/CoreMessageService.cs
  10. +2 −1 src/NuGetGallery.Core/Services/ICoreMessageService.cs
  11. +3 −0 src/NuGetGallery/App_Start/DefaultDependenciesModule.cs
  12. +85 −0 src/NuGetGallery/Areas/Admin/Controllers/LockPackageController.cs
  13. +48 −0 src/NuGetGallery/Areas/Admin/Helpers.cs
  14. +1 −32 src/NuGetGallery/Areas/Admin/Services/ValidationAdminService.cs
  15. +24 −0 src/NuGetGallery/Areas/Admin/ViewModels/LockPackageViewModel.cs
  16. +25 −14 src/NuGetGallery/Areas/Admin/Views/Home/Index.cshtml
  17. +82 −0 src/NuGetGallery/Areas/Admin/Views/LockPackage/Index.cshtml
  18. +8 −1 src/NuGetGallery/Authentication/AuthenticationService.cs
  19. +12 −1 src/NuGetGallery/Configuration/ConfigurationService.cs
  20. +53 −0 src/NuGetGallery/Configuration/IPackageDeleteConfiguration.cs
  21. +14 −0 src/NuGetGallery/Configuration/PackageDeleteConfiguration.cs
  22. +2 −3 src/NuGetGallery/Controllers/ApiController.cs
  23. +1 −0 src/NuGetGallery/Controllers/CuratedFeedsController.cs
  24. +16 −10 src/NuGetGallery/Controllers/JsonApiController.cs
  25. +78 −49 src/NuGetGallery/Controllers/PackagesController.cs
  26. +13 −25 src/NuGetGallery/Controllers/UsersController.cs
  27. +2 −1 src/NuGetGallery/ExtensionMethods.cs
  28. +1 −1 src/NuGetGallery/Extensions/UserExtensions.cs
  29. +1 −2 src/NuGetGallery/Filters/ApiAuthorizeAttribute.cs
  30. +147 −0 src/NuGetGallery/Helpers/PermissionsHelpers.cs
  31. +3 −2 src/NuGetGallery/Infrastructure/Authentication/CredentialBuilder.cs
  32. +1 −1 src/NuGetGallery/Infrastructure/Authentication/ICredentialBuilder.cs
  33. +29 −0 src/NuGetGallery/Migrations/201712211850074_MembershipRequests.Designer.cs
  34. +59 −0 src/NuGetGallery/Migrations/201712211850074_MembershipRequests.cs
  35. +126 −0 src/NuGetGallery/Migrations/201712211850074_MembershipRequests.resx
  36. +32 −10 src/NuGetGallery/NuGetGallery.csproj
  37. +1 −0 src/NuGetGallery/RequestModels/EditPackageRequest.cs
  38. +1 −1 src/NuGetGallery/Scripts/gallery/async-file-upload.js
  39. +2 −2 src/NuGetGallery/Scripts/gallery/page-manage-owners.js
  40. +2 −2 src/NuGetGallery/Scripts/gallery/page-manage-packages.js
  41. +0 −25 src/NuGetGallery/Services/AccountActions.cs
  42. +19 −0 src/NuGetGallery/Services/ActionOnNewPackageContext.cs
  43. +38 −0 src/NuGetGallery/Services/ActionRequiringAccountPermissions.cs
  44. +108 −0 src/NuGetGallery/Services/ActionRequiringEntityPermissions.cs
  45. +61 −0 src/NuGetGallery/Services/ActionRequiringPackagePermissions.cs
  46. +72 −0 src/NuGetGallery/Services/ActionRequiringReservedNamespacePermissions.cs
  47. +82 −0 src/NuGetGallery/Services/ActionsRequiringPermissions.cs
  48. +41 −0 src/NuGetGallery/Services/IActionRequiringEntityPermissions.cs
  49. +1 −1 src/NuGetGallery/Services/IMessageService.cs
  50. +6 −7 src/NuGetGallery/Services/IReservedNamespaceService.cs
  51. +9 −0 src/NuGetGallery/Services/IValidationService.cs
  52. +7 −9 src/NuGetGallery/Services/MessageService.cs
  53. +0 −63 src/NuGetGallery/Services/PackageActions.cs
  54. +19 −1 src/NuGetGallery/Services/PackageDeleteService.cs
  55. +1 −1 src/NuGetGallery/Services/PackageService.cs
  56. +2 −3 src/NuGetGallery/Services/PackageUploadService.cs
  57. +0 −39 src/NuGetGallery/Services/PermissionLevel.cs
  58. +36 −0 src/NuGetGallery/Services/PermissionsCheckResult.cs
  59. +44 −0 src/NuGetGallery/Services/PermissionsRequirement.cs
  60. +0 −152 src/NuGetGallery/Services/PermissionsService.cs
  61. +10 −17 src/NuGetGallery/Services/ReservedNamespaceService.cs
  62. +41 −1 src/NuGetGallery/Services/ValidationService.cs
  63. +6 −2 src/NuGetGallery/ViewModels/DeletePackageViewModel.cs
  64. +7 −5 src/NuGetGallery/ViewModels/DisplayPackageViewModel.cs
  65. +15 −3 src/NuGetGallery/ViewModels/ListPackageItemViewModel.cs
  66. +0 −5 src/NuGetGallery/ViewModels/ListPackageOwnerViewModel.cs
  67. +2 −2 src/NuGetGallery/ViewModels/ManagePackageOwnersViewModel.cs
  68. +5 −2 src/NuGetGallery/ViewModels/PackageListViewModel.cs
  69. +5 −4 src/NuGetGallery/ViewModels/PackageOwnersResultViewModel.cs
  70. +5 −3 src/NuGetGallery/Views/Authentication/SignIn.cshtml
  71. +74 −49 src/NuGetGallery/Views/Packages/Delete.cshtml
  72. +17 −10 src/NuGetGallery/Views/Packages/DisplayPackage.cshtml
  73. +60 −42 src/NuGetGallery/Views/Packages/Edit.cshtml
  74. +2 −2 src/NuGetGallery/Views/Packages/ManagePackageOwners.cshtml
  75. +2 −2 src/NuGetGallery/Views/Packages/_VerifyForm.cshtml
  76. +1 −1 src/NuGetGallery/Views/Packages/_VerifyMetadata.cshtml
  77. +6 −6 src/NuGetGallery/Views/Shared/_ListPackage.cshtml
  78. +4 −8 src/NuGetGallery/Views/Users/Packages.cshtml
  79. +3 −3 src/NuGetGallery/Views/Users/_UserPackagesList.cshtml
  80. +9 −1 src/NuGetGallery/Web.config
  81. +4 −3 src/NuGetGallery/packages.config
  82. +57 −0 tests/NuGetGallery.Facts/Areas/Admin/Controllers/LockPackageControllerFacts.cs
  83. +42 −0 tests/NuGetGallery.Facts/Areas/Admin/HelperFacts.cs
  84. +0 −30 tests/NuGetGallery.Facts/Areas/Admin/Services/ValidationAdminServiceFacts.cs
  85. +20 −0 tests/NuGetGallery.Facts/Authentication/AuthenticationServiceFacts.cs
  86. +2 −2 tests/NuGetGallery.Facts/Authentication/TestCredentialHelper.cs
  87. +9 −10 tests/NuGetGallery.Facts/Controllers/ApiControllerFacts.cs
  88. +23 −73 tests/NuGetGallery.Facts/Controllers/JsonApiControllerFacts.cs
  89. +1,285 −448 tests/NuGetGallery.Facts/Controllers/PackagesControllerFacts.cs
  90. +122 −4 tests/NuGetGallery.Facts/Controllers/UsersControllerFacts.cs
  91. +46 −0 tests/NuGetGallery.Facts/ExtensionMethodsFacts.cs
  92. +5 −0 tests/NuGetGallery.Facts/Framework/Fakes.cs
  93. +13 −0 tests/NuGetGallery.Facts/Framework/MemberDataHelper.cs
  94. +16 −2 tests/NuGetGallery.Facts/Framework/TestExtensionMethods.cs
  95. +25 −7 tests/NuGetGallery.Facts/NuGetGallery.Facts.csproj
  96. +195 −0 tests/NuGetGallery.Facts/Services/ActionRequiringEntityPermissionsFacts.cs
  97. +107 −28 tests/NuGetGallery.Facts/Services/MessageServiceFacts.cs
  98. +75 −17 tests/NuGetGallery.Facts/Services/PackageDeleteServiceFacts.cs
  99. +14 −6 tests/NuGetGallery.Facts/Services/PackageUploadServiceFacts.cs
  100. +138 −0 tests/NuGetGallery.Facts/Services/PermissionsHelpersFacts.cs
  101. +0 −138 tests/NuGetGallery.Facts/Services/PermissionsServiceFacts.cs
  102. +22 −15 tests/NuGetGallery.Facts/Services/ReservedNamespaceServiceFacts.cs
  103. +97 −1 tests/NuGetGallery.Facts/Services/ValidationServiceFacts.cs
  104. +72 −0 tests/NuGetGallery.Facts/TestData.Designer.cs
  105. +123 −0 tests/NuGetGallery.Facts/TestData.resx
  106. +33 −7 tests/NuGetGallery.Facts/TestUtils/TestUtility.cs
  107. +4 −4 tests/NuGetGallery.Facts/UrlExtensionsFacts.cs
  108. +1 −1 tests/NuGetGallery.Facts/ViewModels/DeleteAccountViewModelFacts.cs
  109. +11 −11 tests/NuGetGallery.Facts/ViewModels/DisplayPackageViewModelFacts.cs
  110. +15 −15 tests/NuGetGallery.Facts/ViewModels/ListPackageItemViewModelFacts.cs
  111. +1 −1 tests/NuGetGallery.Facts/ViewModels/UserProfileModelFacts.cs
  112. +4 −3 tests/NuGetGallery.Facts/packages.config
  113. +23 −0 tests/NuGetGallery.FunctionalTests.Core/EnvironmentSettings.cs
  114. +1 −0 tests/NuGetGallery.FunctionalTests.Core/NuGetGallery.FunctionalTests.Core.csproj
  115. +0 −1 ...NuGetGallery.FunctionalTests.Core/XunitExtensions/DefaultSecurityPoliciesEnforcedFactAttribute.cs
  116. +18 −0 tests/NuGetGallery.FunctionalTests.Core/XunitExtensions/PackageLockFactAttribute.cs
  117. +32 −0 tests/NuGetGallery.FunctionalTests/Commandline/NuGetCommandLineTests.cs
@@ -17,6 +17,10 @@ namespace NuGetGallery.Auditing
{
public class AuditActor
{
+ private static string _localIpAddress;
+ private static DateTime _localIpAddressExpiration;
+ private const int _localIpAddressExpirationInMinutes = 10;
+
public string MachineName { get; set; }
[Obfuscate(ObfuscationType.IP)]
@@ -114,20 +118,28 @@ public static Task<AuditActor> GetCurrentMachineActorAsync()
onBehalfOf);
}
+ /// <summary>
+ /// Get the local machine's IP address.
+ /// Note that this method is cached because the IP shouldn't change frequently, and the
+ /// GetIsNetworkAvailable call is expensive.
+ /// </summary>
public static async Task<string> GetLocalIpAddressAsync()
{
- string ipAddress = null;
- if (NetworkInterface.GetIsNetworkAvailable())
+ if (string.IsNullOrEmpty(_localIpAddress) || DateTime.UtcNow >= _localIpAddressExpiration)
{
- var entry = await Dns.GetHostEntryAsync(Dns.GetHostName());
- if (entry != null)
+ if (NetworkInterface.GetIsNetworkAvailable())
{
- ipAddress =
- TryGetAddress(entry.AddressList, AddressFamily.InterNetworkV6) ??
- TryGetAddress(entry.AddressList, AddressFamily.InterNetwork);
+ var entry = await Dns.GetHostEntryAsync(Dns.GetHostName());
+ if (entry != null)
+ {
+ _localIpAddress =
+ TryGetAddress(entry.AddressList, AddressFamily.InterNetworkV6) ??
+ TryGetAddress(entry.AddressList, AddressFamily.InterNetwork);
+ _localIpAddressExpiration = DateTime.UtcNow.AddMinutes(_localIpAddressExpirationInMinutes);
+ }
}
}
- return ipAddress;
+ return _localIpAddress;
}
private static string TryGetAddress(IEnumerable<IPAddress> addrs, AddressFamily family)
@@ -65,6 +65,9 @@ public Credential(string type, string value, TimeSpan? expiration)
[StringLength(maximumLength: 256)]
public string Value { get; set; }
+ [StringLength(maximumLength: 256)]
+ public string TenantId { get; set; }
+
[StringLength(maximumLength: 256)]
public string Description { get; set; }
@@ -140,18 +140,40 @@ protected override void OnModelCreating(DbModelBuilder modelBuilder)
modelBuilder.Entity<Membership>()
.HasKey(m => new { m.OrganizationKey, m.MemberKey });
+ modelBuilder.Entity<MembershipRequest>()
+ .HasKey(m => new { m.OrganizationKey, m.NewMemberKey });
+
+ modelBuilder.Entity<OrganizationMigrationRequest>()
+ .HasKey(m => m.NewOrganizationKey);
+
modelBuilder.Entity<User>()
.HasMany(u => u.Organizations)
.WithRequired(m => m.Member)
.HasForeignKey(m => m.MemberKey)
.WillCascadeOnDelete(true); // Membership will be deleted with the Member account.
+ modelBuilder.Entity<User>()
+ .HasMany(u => u.OrganizationRequests)
+ .WithRequired(m => m.NewMember)
+ .HasForeignKey(m => m.NewMemberKey)
+ .WillCascadeOnDelete(false);
+
+ modelBuilder.Entity<User>()
+ .HasOptional(u => u.OrganizationMigrationRequest)
+ .WithRequired(m => m.NewOrganization);
+
modelBuilder.Entity<Organization>()
.HasMany(o => o.Members)
.WithRequired(m => m.Organization)
.HasForeignKey(m => m.OrganizationKey)
.WillCascadeOnDelete(true); // Memberships will be deleted with the Organization account.
+ modelBuilder.Entity<Organization>()
+ .HasMany(o => o.MemberRequests)
+ .WithRequired(m => m.Organization)
+ .HasForeignKey(m => m.OrganizationKey)
+ .WillCascadeOnDelete(false);
+
modelBuilder.Entity<Role>()
.HasKey(u => u.Key);
@@ -0,0 +1,26 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.ComponentModel.DataAnnotations;
+
+namespace NuGetGallery
+{
+ public class MembershipRequest
+ {
+ public int OrganizationKey { get; set; }
+
+ public virtual Organization Organization { get; set; }
+
+ public int NewMemberKey { get; set; }
+
+ public virtual User NewMember { get; set; }
+
+ public bool IsAdmin { get; set; }
+
+ [Required]
+ public string ConfirmationToken { get; set; }
+
+ public DateTime RequestDate { get; set; }
+ }
+}
@@ -29,5 +29,10 @@ public Organization(string name) : base(name)
/// Organization Memberships to this organization.
/// </summary>
public virtual ICollection<Membership> Members { get; set; }
+
+ /// <summary>
+ /// Requests to become a member of this <see cref="Organization"/>.
+ /// </summary>
+ public virtual ICollection<MembershipRequest> MemberRequests { get; set; }
}
}
@@ -0,0 +1,24 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.ComponentModel.DataAnnotations;
+
+namespace NuGetGallery
+{
+ public class OrganizationMigrationRequest
+ {
+ public int NewOrganizationKey { get; set; }
+
+ public virtual User NewOrganization { get; set; }
+
+ public int AdminUserKey { get; set; }
+
+ public virtual User AdminUser { get; set; }
+
+ [Required]
+ public string ConfirmationToken { get; set; }
+
+ public DateTime RequestDate { get; set; }
+ }
+}
@@ -32,10 +32,20 @@ public User(string username)
}
/// <summary>
- /// Organization memberships for a non-organization <see cref="User"/> account.
+ /// Organization memberships, for a non-organization <see cref="User"/> account.
/// </summary>
public virtual ICollection<Membership> Organizations { get; set; }
+ /// <summary>
+ /// Organization membership requests, for a non-organization <see cref="User"/> account.
+ /// </summary>
+ public virtual ICollection<MembershipRequest> OrganizationRequests { get; set; }
+
+ /// <summary>
+ /// Request to transform a <see cref="User"/> account into an <see cref="Organization"/> account.
+ /// </summary>
+ public virtual OrganizationMigrationRequest OrganizationMigrationRequest { get; set; }
+
[StringLength(256)]
public string EmailAddress { get; set; }
@@ -174,6 +174,8 @@
<Compile Include="Entities\Membership.cs" />
<Compile Include="Entities\Organization.cs" />
<Compile Include="Entities\AccountDelete.cs" />
+ <Compile Include="Entities\MembershipRequest.cs" />
+ <Compile Include="Entities\OrganizationMigrationRequest.cs" />
<Compile Include="Entities\PackageDelete.cs" />
<Compile Include="Entities\EmailMessage.cs" />
<Compile Include="Entities\EntitiesConfiguration.cs" />
@@ -62,16 +62,41 @@ public void SendPackageAddedNotice(Package package, string packageUrl, string pa
}
}
- public void SendPackageValidationFailedNotice(Package package, string packageUrl, string packageSupportUrl, string emailSettingsUrl)
+ public void SendPackageValidationFailedNotice(Package package, string packageUrl, string packageSupportUrl)
{
string subject = "[{0}] Package validation failed - {1} {2}";
- string body = @"The package [{1} {2}]({3}) failed validation and was therefore not published on {0}. Note that the package will not be available for consumption and you will not be able to push the same package ID and version until further action is taken. Please [contact support]({4}) for next steps.
+ string body = @"The package [{1} {2}]({3}) failed validation and was therefore not published on {0}. Note that the package will not be available for consumption and you will not be able to push the same package ID and version until further action is taken. Please [contact support]({4}) for next steps.";
------------------------------------------------
-<em style=""font-size: 0.8em;"">
- To stop receiving emails as an owner of this package, sign in to the {0} and
- [change your email notification settings]({5}).
-</em>";
+ body = string.Format(
+ CultureInfo.CurrentCulture,
+ body,
+ CoreConfiguration.GalleryOwner.DisplayName,
+ package.PackageRegistration.Id,
+ package.Version,
+ packageUrl,
+ packageSupportUrl);
+
+ subject = string.Format(CultureInfo.CurrentCulture, subject, CoreConfiguration.GalleryOwner.DisplayName, package.PackageRegistration.Id, package.Version);
+
+ using (var mailMessage = new MailMessage())
+ {
+ mailMessage.Subject = subject;
+ mailMessage.Body = body;
+ mailMessage.From = CoreConfiguration.GalleryNoReplyAddress;
+
+ AddAllOwnersToMailMessage(package.PackageRegistration, mailMessage);
+
+ if (mailMessage.To.Any())
+ {
+ SendMessage(mailMessage, copySender: false);
+ }
+ }
+ }
+
+ public void SendSignedPackageNotAllowedNotice(Package package, string packageUrl, string announcementsUrl, string twitterUrl)
+ {
+ string subject = "[{0}] Package validation failed - {1} {2}";
+ string body = @"The package [{1} {2}]({3}) could not be published since it is signed. {0} does not accept signed packages at this moment. To be notified when {0} starts accepting signed packages, and more, watch our [Announcements]({4}) page or follow us on [Twitter]({5}).";
body = string.Format(
CultureInfo.CurrentCulture,
@@ -80,8 +105,8 @@ public void SendPackageValidationFailedNotice(Package package, string packageUrl
package.PackageRegistration.Id,
package.Version,
packageUrl,
- packageSupportUrl,
- emailSettingsUrl);
+ announcementsUrl,
+ twitterUrl);
subject = string.Format(CultureInfo.CurrentCulture, subject, CoreConfiguration.GalleryOwner.DisplayName, package.PackageRegistration.Id, package.Version);
@@ -91,7 +116,7 @@ public void SendPackageValidationFailedNotice(Package package, string packageUrl
mailMessage.Body = body;
mailMessage.From = CoreConfiguration.GalleryNoReplyAddress;
- AddOwnersSubscribedToPackagePushedNotification(package.PackageRegistration, mailMessage);
+ AddAllOwnersToMailMessage(package.PackageRegistration, mailMessage);
if (mailMessage.To.Any())
{
@@ -100,6 +125,14 @@ public void SendPackageValidationFailedNotice(Package package, string packageUrl
}
}
+ protected static void AddAllOwnersToMailMessage(PackageRegistration packageRegistration, MailMessage mailMessage)
+ {
+ foreach (var owner in packageRegistration.Owners)
+ {
+ mailMessage.To.Add(owner.ToMailAddress());
+ }
+ }
+
protected static void AddOwnersToMailMessage(PackageRegistration packageRegistration, MailMessage mailMessage)
{
foreach (var owner in packageRegistration.Owners.Where(o => o.EmailAllowed))
@@ -6,6 +6,7 @@ namespace NuGetGallery.Services
public interface ICoreMessageService
{
void SendPackageAddedNotice(Package package, string packageUrl, string packageSupportUrl, string emailSettingsUrl);
- void SendPackageValidationFailedNotice(Package package, string packageUrl, string packageSupportUrl, string emailSettingsUrl);
+ void SendPackageValidationFailedNotice(Package package, string packageUrl, string packageSupportUrl);
+ void SendSignedPackageNotAllowedNotice(Package package, string packageUrl, string announcementsUrl, string twitterUrl);
}
}
@@ -72,6 +72,9 @@ protected override void Load(ContainerBuilder builder)
.AsSelf()
.As<FeatureConfiguration>();
+ builder.Register(c => configuration.PackageDelete)
+ .As<IPackageDeleteConfiguration>();
+
builder.RegisterType<TelemetryService>().As<ITelemetryService>().SingleInstance();
builder.RegisterType<CredentialBuilder>().As<ICredentialBuilder>().SingleInstance();
builder.RegisterType<CredentialValidator>().As<ICredentialValidator>().SingleInstance();
@@ -0,0 +1,85 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Web.Mvc;
+using NuGetGallery.Areas.Admin.ViewModels;
+
+namespace NuGetGallery.Areas.Admin.Controllers
+{
+ public class LockPackageController : AdminControllerBase
+ {
+ private IEntityRepository<PackageRegistration> _packageRegistrationRepository;
+
+ public LockPackageController(IEntityRepository<PackageRegistration> packageRegistrationRepository)
+ {
+ _packageRegistrationRepository = packageRegistrationRepository ?? throw new ArgumentNullException(nameof(packageRegistrationRepository));
+ }
+
+ [HttpGet]
+ public virtual ActionResult Index()
+ {
+ var model = new LockPackageViewModel();
+
+ return View(model);
+ }
+
+ [HttpGet]
+ public virtual ActionResult Search(string query)
+ {
+ var lines = Helpers.ParseQueryToLines(query);
+ var packageRegistrations = GetPackageRegistrationsForIds(lines);
+
+ return View(nameof(Index), new LockPackageViewModel()
+ {
+ Query = query,
+ PackageLockStates = packageRegistrations.Select(x => new PackageLockState() { Id = x.Id, IsLocked = x.IsLocked }).ToList()
+ });
+ }
+
+ [HttpPost]
+ [ValidateAntiForgeryToken]
+ public async Task<ActionResult> Update(LockPackageViewModel lockPackageViewModel)
+ {
+ int counter = 0;
+
+ if (lockPackageViewModel != null && lockPackageViewModel.PackageLockStates != null)
+ {
+ var packageIdsFromRequest = lockPackageViewModel.PackageLockStates.Select(x => x.Id).ToList();
+ var packageRegistrationsFromDb = GetPackageRegistrationsForIds(packageIdsFromRequest);
+
+ var packageStatesFromRequestDictionary = lockPackageViewModel.PackageLockStates.ToDictionary(x => x.Id);
+
+ foreach (var packageRegistration in packageRegistrationsFromDb)
+ {
+ if (packageStatesFromRequestDictionary.TryGetValue(packageRegistration.Id, out var packageStateRequest))
+ {
+ if (packageRegistration.IsLocked != packageStateRequest.IsLocked)
+ {
+ packageRegistration.IsLocked = packageStateRequest.IsLocked;
+ counter++;
+ }
+ }
+ }
+
+ if (counter > 0)
+ {
+ await _packageRegistrationRepository.CommitChangesAsync();
+ }
+ }
+
+ TempData["Message"] = string.Format(CultureInfo.InvariantCulture, $"Lock state was updated for {counter} packages.");
+
+ return View(nameof(Index), lockPackageViewModel);
+ }
+
+ private IList<PackageRegistration> GetPackageRegistrationsForIds(IReadOnlyList<string> ids)
+ {
+ return _packageRegistrationRepository.GetAll().Where(x => ids.Contains(x.Id)).ToList();
+ }
+ }
+}
Oops, something went wrong.

0 comments on commit c60dcba

Please sign in to comment.