Skip to content

Commit

Permalink
Merge pull request #5245 from NuGet/dev
Browse files Browse the repository at this point in the history
[ReleasePrep][2018.01.18] RI of dev into master
  • Loading branch information
loic-sharma authored Jan 9, 2018
2 parents 45431c3 + b742b6c commit c60dcba
Show file tree
Hide file tree
Showing 117 changed files with 4,505 additions and 1,473 deletions.
28 changes: 20 additions & 8 deletions src/NuGetGallery.Core/Auditing/AuditActor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -114,20 +118,28 @@ public static async Task<AuditActor> GetCurrentMachineActorAsync(AuditActor onBe
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)
Expand Down
3 changes: 3 additions & 0 deletions src/NuGetGallery.Core/Entities/Credential.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

Expand Down
22 changes: 22 additions & 0 deletions src/NuGetGallery.Core/Entities/EntitiesContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
26 changes: 26 additions & 0 deletions src/NuGetGallery.Core/Entities/MembershipRequest.cs
Original file line number Diff line number Diff line change
@@ -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; }
}
}
5 changes: 5 additions & 0 deletions src/NuGetGallery.Core/Entities/Organization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
}
}
24 changes: 24 additions & 0 deletions src/NuGetGallery.Core/Entities/OrganizationMigrationRequest.cs
Original file line number Diff line number Diff line change
@@ -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; }
}
}
12 changes: 11 additions & 1 deletion src/NuGetGallery.Core/Entities/User.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

Expand Down
2 changes: 2 additions & 0 deletions src/NuGetGallery.Core/NuGetGallery.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -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" />
Expand Down
53 changes: 43 additions & 10 deletions src/NuGetGallery.Core/Services/CoreMessageService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,41 @@ [change your email notification settings]({5}).
}
}

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,
Expand All @@ -80,8 +105,8 @@ [change your email notification settings]({5}).
package.PackageRegistration.Id,
package.Version,
packageUrl,
packageSupportUrl,
emailSettingsUrl);
announcementsUrl,
twitterUrl);

subject = string.Format(CultureInfo.CurrentCulture, subject, CoreConfiguration.GalleryOwner.DisplayName, package.PackageRegistration.Id, package.Version);

Expand All @@ -91,7 +116,7 @@ [change your email notification settings]({5}).
mailMessage.Body = body;
mailMessage.From = CoreConfiguration.GalleryNoReplyAddress;

AddOwnersSubscribedToPackagePushedNotification(package.PackageRegistration, mailMessage);
AddAllOwnersToMailMessage(package.PackageRegistration, mailMessage);

if (mailMessage.To.Any())
{
Expand All @@ -100,6 +125,14 @@ [change your email notification settings]({5}).
}
}

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))
Expand Down
3 changes: 2 additions & 1 deletion src/NuGetGallery.Core/Services/ICoreMessageService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
3 changes: 3 additions & 0 deletions src/NuGetGallery/App_Start/DefaultDependenciesModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
85 changes: 85 additions & 0 deletions src/NuGetGallery/Areas/Admin/Controllers/LockPackageController.cs
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
Loading

0 comments on commit c60dcba

Please sign in to comment.