Skip to content

Commit 08a662d

Browse files
authored
[Rename] Display rename information on package detail page (#7964)
* Initial commit * Fix * Tests * Fix CI * Test Coverage * Handle feedback * Protection * Behind feture flag
1 parent 6ea4722 commit 08a662d

18 files changed

Lines changed: 404 additions & 9 deletions

src/NuGetGallery.Services/Configuration/FeatureFlagService.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public class FeatureFlagService : IFeatureFlagService
3535
private const string ShowEnable2FADialog = GalleryPrefix + "ShowEnable2FADialog";
3636
private const string Get2FADismissFeedback = GalleryPrefix + "Get2FADismissFeedback";
3737
private const string UsabillaOnEveryPageFeatureName = GalleryPrefix + "UsabillaEveryPage";
38+
private const string PackageRenamesFeatureName = GalleryPrefix + "PackageRenames";
3839

3940
private readonly IFeatureFlagClient _client;
4041

@@ -173,5 +174,10 @@ public bool IsUsabillaButtonEnabledOnEveryPage()
173174
{
174175
return _client.IsEnabled(UsabillaOnEveryPageFeatureName, defaultValue: false);
175176
}
177+
178+
public bool IsPackageRenamesEnabled(User user)
179+
{
180+
return _client.IsEnabled(PackageRenamesFeatureName, user, defaultValue: false);
181+
}
176182
}
177183
}

src/NuGetGallery.Services/Configuration/IFeatureFlagService.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4-
using NuGet.Services.Entities;
54
using System.Collections.Generic;
5+
using NuGet.Services.Entities;
66

77
namespace NuGetGallery
88
{
@@ -79,7 +79,7 @@ public interface IFeatureFlagService
7979
/// <param name="user">The user to test for the Flight</param>
8080
/// <returns>Whether or not the Flight is enabled for the user</returns>
8181
bool IsGitHubUsageEnabled(User user);
82-
82+
8383
/// <summary>
8484
/// Whether the OData controllers use the read-only replica.
8585
/// </summary>
@@ -125,5 +125,10 @@ public interface IFeatureFlagService
125125
/// Whether we should enable the Usabilla feedback button on every page.
126126
/// </summary>
127127
bool IsUsabillaButtonEnabledOnEveryPage();
128+
129+
/// <summary>
130+
/// Whether the user is able to see or manage the package renames information.
131+
/// </summary>
132+
bool IsPackageRenamesEnabled(User user);
128133
}
129134
}

src/NuGetGallery/App_Start/DefaultDependenciesModule.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,11 @@ protected override void Load(ContainerBuilder builder)
264264
.As<IEntityRepository<PackageDeprecation>>()
265265
.InstancePerLifetimeScope();
266266

267+
builder.RegisterType<EntityRepository<PackageRename>>()
268+
.AsSelf()
269+
.As<IEntityRepository<PackageRename>>()
270+
.InstancePerLifetimeScope();
271+
267272
ConfigureGalleryReadOnlyReplicaEntitiesContext(builder, loggerFactory, configuration, secretInjector);
268273

269274
var supportDbConnectionFactory = CreateDbConnectionFactory(
@@ -412,6 +417,10 @@ protected override void Load(ContainerBuilder builder)
412417
.As<IPackageDeprecationService>()
413418
.InstancePerLifetimeScope();
414419

420+
builder.RegisterType<PackageRenameService>()
421+
.As<IPackageRenameService>()
422+
.InstancePerLifetimeScope();
423+
415424
builder.RegisterType<PackageUpdateService>()
416425
.As<IPackageUpdateService>()
417426
.InstancePerLifetimeScope();

src/NuGetGallery/Controllers/PackagesController.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ public partial class PackagesController
119119
private readonly ILicenseExpressionSplitter _licenseExpressionSplitter;
120120
private readonly IFeatureFlagService _featureFlagService;
121121
private readonly IPackageDeprecationService _deprecationService;
122+
private readonly IPackageRenameService _renameService;
122123
private readonly IABTestService _abTestService;
123124
private readonly IIconUrlProvider _iconUrlProvider;
124125
private readonly DisplayPackageViewModelFactory _displayPackageViewModelFactory;
@@ -157,6 +158,7 @@ public PackagesController(
157158
ILicenseExpressionSplitter licenseExpressionSplitter,
158159
IFeatureFlagService featureFlagService,
159160
IPackageDeprecationService deprecationService,
161+
IPackageRenameService renameService,
160162
IABTestService abTestService,
161163
IIconUrlProvider iconUrlProvider)
162164
{
@@ -189,6 +191,7 @@ public PackagesController(
189191
_licenseExpressionSplitter = licenseExpressionSplitter ?? throw new ArgumentNullException(nameof(licenseExpressionSplitter));
190192
_featureFlagService = featureFlagService ?? throw new ArgumentNullException(nameof(featureFlagService));
191193
_deprecationService = deprecationService ?? throw new ArgumentNullException(nameof(deprecationService));
194+
_renameService = renameService ?? throw new ArgumentNullException(nameof(renameService));
192195
_abTestService = abTestService ?? throw new ArgumentNullException(nameof(abTestService));
193196
_iconUrlProvider = iconUrlProvider ?? throw new ArgumentNullException(nameof(iconUrlProvider));
194197

@@ -823,11 +826,18 @@ public virtual async Task<ActionResult> DisplayPackage(string id, string version
823826
.GroupBy(d => d.PackageKey)
824827
.ToDictionary(g => g.Key, g => g.First());
825828

829+
IReadOnlyList<PackageRename> packageRenames = null;
830+
if (_featureFlagService.IsPackageRenamesEnabled(currentUser))
831+
{
832+
packageRenames = _renameService.GetPackageRenames(package.PackageRegistration);
833+
}
834+
826835
var model = _displayPackageViewModelFactory.Create(
827836
package,
828837
allVersions,
829838
currentUser,
830839
packageKeyToDeprecation,
840+
packageRenames,
831841
readme);
832842

833843
model.ValidatingTooLong = _validationService.IsValidatingTooLong(package);
@@ -836,8 +846,9 @@ public virtual async Task<ActionResult> DisplayPackage(string id, string version
836846
model.IsCertificatesUIEnabled = _contentObjectService.CertificatesConfiguration?.IsUIEnabledForUser(currentUser) ?? false;
837847
model.IsAtomFeedEnabled = _featureFlagService.IsPackagesAtomFeedEnabled();
838848
model.IsPackageDeprecationEnabled = _featureFlagService.IsManageDeprecationEnabled(currentUser, allVersions);
849+
model.IsPackageRenamesEnabled = _featureFlagService.IsPackageRenamesEnabled(currentUser);
839850

840-
if(model.IsGitHubUsageEnabled = _featureFlagService.IsGitHubUsageEnabled(currentUser))
851+
if (model.IsGitHubUsageEnabled = _featureFlagService.IsGitHubUsageEnabled(currentUser))
841852
{
842853
model.GitHubDependenciesInformation = _contentObjectService.GitHubUsageConfiguration.GetPackageInformation(id);
843854
}

src/NuGetGallery/Helpers/ViewModelExtensions/DeletePackageViewModelFactory.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public DeletePackageViewModel Setup(
3939
allVersions,
4040
currentUser,
4141
packageKeyToDeprecation: null,
42+
packageRenames: null,
4243
readmeResult: null);
4344

4445
return SetupInternal(viewModel, package, reasons);

src/NuGetGallery/Helpers/ViewModelExtensions/DisplayPackageViewModelFactory.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public DisplayPackageViewModel Create(
2323
IReadOnlyCollection<Package> allVersions,
2424
User currentUser,
2525
IReadOnlyDictionary<int, PackageDeprecation> packageKeyToDeprecation,
26+
IReadOnlyList<PackageRename> packageRenames,
2627
RenderedReadMeResult readmeResult)
2728
{
2829
var viewModel = new DisplayPackageViewModel();
@@ -32,6 +33,7 @@ public DisplayPackageViewModel Create(
3233
allVersions,
3334
currentUser,
3435
packageKeyToDeprecation,
36+
packageRenames,
3537
readmeResult);
3638
}
3739

@@ -41,11 +43,12 @@ public DisplayPackageViewModel Setup(
4143
IReadOnlyCollection<Package> allVersions,
4244
User currentUser,
4345
IReadOnlyDictionary<int, PackageDeprecation> packageKeyToDeprecation,
46+
IReadOnlyList<PackageRename> packageRenames,
4447
RenderedReadMeResult readmeResult)
4548
{
4649
_listPackageItemViewModelFactory.Setup(viewModel, package, currentUser);
4750
SetupCommon(viewModel, package, pushedBy: null, packageKeyToDeprecation: packageKeyToDeprecation);
48-
return SetupInternal(viewModel, package, allVersions, currentUser, packageKeyToDeprecation, readmeResult);
51+
return SetupInternal(viewModel, package, allVersions, currentUser, packageKeyToDeprecation, packageRenames, readmeResult);
4952
}
5053

5154
private DisplayPackageViewModel SetupInternal(
@@ -54,6 +57,7 @@ private DisplayPackageViewModel SetupInternal(
5457
IReadOnlyCollection<Package> allVersions,
5558
User currentUser,
5659
IReadOnlyDictionary<int, PackageDeprecation> packageKeyToDeprecation,
60+
IReadOnlyList<PackageRename> packageRenames,
5761
RenderedReadMeResult readmeResult)
5862
{
5963
var dependencies = package.Dependencies.ToList();
@@ -112,6 +116,15 @@ private DisplayPackageViewModel SetupInternal(
112116
viewModel.CustomMessage = deprecation.CustomMessage;
113117
}
114118

119+
if (packageRenames != null && packageRenames.Count != 0)
120+
{
121+
viewModel.PackageRenames = packageRenames;
122+
if (package.PackageRegistration?.RenamedMessage != null)
123+
{
124+
viewModel.RenamedMessage = package.PackageRegistration.RenamedMessage;
125+
}
126+
}
127+
115128
viewModel.ReadMeHtml = readmeResult?.Content;
116129
viewModel.ReadMeImagesRewritten = readmeResult != null ? readmeResult.ImagesRewritten : false;
117130
viewModel.HasEmbeddedIcon = package.HasEmbeddedIcon;

src/NuGetGallery/NuGetGallery.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,7 @@
487487
<Compile Include="Services\GalleryContentFileMetadataService.cs" />
488488
<Compile Include="Services\InvalidLicenseUrlValidationMessage.cs" />
489489
<Compile Include="Services\InvalidUrlEncodingForLicenseUrlValidationMessage.cs" />
490+
<Compile Include="Services\IPackageRenameService.cs" />
490491
<Compile Include="Services\ISearchSideBySideService.cs" />
491492
<Compile Include="Services\ISymbolPackageUploadService.cs" />
492493
<Compile Include="Services\ISymbolPackageFileService.cs" />
@@ -498,6 +499,7 @@
498499
<Compile Include="Services\PackageDeleteService.cs" />
499500
<Compile Include="Services\PackageDeprecationManagementService.cs" />
500501
<Compile Include="Services\PackageDeprecationService.cs" />
502+
<Compile Include="Services\PackageRenameService.cs" />
501503
<Compile Include="Services\PackageShouldNotBeSignedUserFixableValidationMessage.cs" />
502504
<Compile Include="Services\PlainTextOnlyValidationMessage.cs" />
503505
<Compile Include="Services\RenderedReadMeResult.cs" />
@@ -2284,6 +2286,9 @@
22842286
<Version>9.3.3</Version>
22852287
</PackageReference>
22862288
</ItemGroup>
2289+
<ItemGroup>
2290+
<Content Include="Views\Packages\_DisplayPackageRenames.cshtml" />
2291+
</ItemGroup>
22872292
<PropertyGroup>
22882293
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
22892294
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>

src/NuGetGallery/Scripts/gallery/page-display-package.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
$(function () {
22
'use strict';
33

4+
// Configure the rename information container
5+
window.nuget.configureExpander("rename-content-container", "ChevronDown", null, "ChevronUp");
6+
configureExpanderWithEnterKeydown($('#show-rename-content-container'));
7+
48
// Configure the deprecation information container
59
var container = $('#show-deprecation-content-container');
610
if ($('#deprecation-content-container').children().length) {
711
// If the deprecation information container has content, configure it as an expander.
812
window.nuget.configureExpander("deprecation-content-container", "ChevronDown", null, "ChevronUp");
9-
container.keydown(function (event) {
10-
if (event.which === 13) { // Enter
11-
$(event.target).click();
12-
}
13-
});
13+
configureExpanderWithEnterKeydown(container)
1414
}
1515
else {
1616
// If the container does not have content, remove its expander attributes
@@ -25,6 +25,15 @@ $(function () {
2525
$('#deprecation-expander-icon-right').hide();
2626
}
2727

28+
// Configure expander with enter keydown event
29+
function configureExpanderWithEnterKeydown(container) {
30+
container.keydown(function (event) {
31+
if (event.which === 13) { // Enter
32+
$(event.target).click();
33+
}
34+
});
35+
}
36+
2837
// Configure ReadMe container
2938
var readmeContainer = $("#readme-container");
3039
if (readmeContainer[0])
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Collections.Generic;
5+
using NuGet.Services.Entities;
6+
7+
namespace NuGetGallery
8+
{
9+
public interface IPackageRenameService
10+
{
11+
IReadOnlyList<PackageRename> GetPackageRenames(PackageRegistration package);
12+
}
13+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Linq;
6+
using System.Data.Entity;
7+
using System.Collections.Generic;
8+
using NuGet.Services.Entities;
9+
10+
namespace NuGetGallery
11+
{
12+
public class PackageRenameService : IPackageRenameService
13+
{
14+
private readonly IEntityRepository<PackageRename> _packageRenameRepository;
15+
16+
public PackageRenameService (
17+
IEntityRepository<PackageRename> packageRenameRepository)
18+
{
19+
_packageRenameRepository = packageRenameRepository ?? throw new ArgumentNullException(nameof(packageRenameRepository));
20+
}
21+
22+
public IReadOnlyList<PackageRename> GetPackageRenames(PackageRegistration packageRegistration)
23+
{
24+
return _packageRenameRepository.GetAll()
25+
.Where(pr => pr.FromPackageRegistrationKey == packageRegistration.Key)
26+
.Include(pr => pr.ToPackageRegistration)
27+
.ToList();
28+
}
29+
}
30+
}

0 commit comments

Comments
 (0)