Skip to content

Commit

Permalink
Finished implementing Web UI. 🎉
Browse files Browse the repository at this point in the history
  • Loading branch information
Emzi0767 committed Jul 5, 2019
1 parent 226248d commit c735cf7
Show file tree
Hide file tree
Showing 34 changed files with 14,270 additions and 38 deletions.
161 changes: 152 additions & 9 deletions src/SlimGet/Controllers/GalleryController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@
// limitations under the License.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using NuGet.Frameworks;
using NuGet.Versioning;
using SlimGet.Data.Configuration;
using SlimGet.Data.Database;
using SlimGet.Models;
using SlimGet.Services;

Expand All @@ -49,17 +53,74 @@ public async Task<IActionResult> Index(CancellationToken cancellationToken)
return this.View(new GalleryIndexModel(pkgCount, verCount));
}

[HttpGet, SlimGetRoute(Routing.GalleryPackageIndexRouteName)]
public IActionResult Packages()
=> this.View();
[HttpGet, SlimGetRoute(Routing.GalleryListRouteName)]
public async Task<IActionResult> Packages([FromQuery] int skip, CancellationToken cancellationToken)
{
if (skip < 0)
return this.BadRequest();

var dbpackages = this.Database.Packages
.Include(x => x.Tags)
.Include(x => x.Authors)
.Include(x => x.Versions)
.OrderByDescending(x => x.DownloadCount)
.ThenBy(x => x.Id);

var count = await dbpackages.CountAsync(cancellationToken);
var next = skip + 20 <= count ? skip + 20 : -1;

return this.View(new GalleryPackageListModel(count, this.PreparePackages(dbpackages.Skip(skip).Take(20)), next, skip - 20));
}

[HttpGet, SlimGetRoute(Routing.GalleryPackageRouteName)]
public async Task<IActionResult> Package(string id, string version, CancellationToken cancellationToken)
{
var dbpackage = await this.Database.Packages
.Include(x => x.Tags)
.Include(x => x.Versions)
.ThenInclude(x => x.Binaries)
.ThenInclude(x => x.PackageSymbols)
.Include(x => x.Versions)
.ThenInclude(x => x.Dependencies)
.Include(x => x.Authors)
.FirstOrDefaultAsync(x => x.Id == id, cancellationToken).ConfigureAwait(false);

if (dbpackage == null)
return this.NotFound();

var dbversion = version != null
? dbpackage.Versions.FirstOrDefault(x => x.Version == version)
: dbpackage.Versions.OrderByDescending(x => x.NuGetVersion).First();

if (dbversion == null)
return this.NotFound();

return this.View(this.PreparePackage(dbpackage, dbversion));
}

[HttpGet, SlimGetRoute(Routing.GallerySearchRouteName)]
public async Task<IActionResult> Search([FromQuery] GallerySearchModel search, CancellationToken cancellationToken)
{
var query = search.Query;
var prerelease = search.Prerelease;
var skip = search.Skip;
var dbpackages = this.Database.Packages
.Include(x => x.Versions)
.Include(x => x.Tags)
.Include(x => x.Authors)
.Where(x => (EF.Functions.Similarity(x.Id, query) >= 0.35 ||
EF.Functions.Similarity(x.Description, query) >= 0.2 ||
EF.Functions.Similarity(x.Title, query) >= 0.2 ||
x.Tags.Any(y => EF.Functions.Similarity(y.Tag, query) >= 0.35)) &&
x.Versions.Any(y => !y.IsPrerelase || prerelease))
.OrderByDescending(x => x.DownloadCount)
.ThenBy(x => x.Id);

[HttpGet, SlimGetRoute(Routing.GalleryPackageDetailsRouteName)]
public IActionResult Packages(string id)
=> this.View();
var count = await dbpackages.CountAsync(cancellationToken);
var next = skip + 20 <= count ? skip + 20 : -1;

[HttpGet, SlimGetRoute(Routing.GalleryPackageVersionRouteName)]
public IActionResult Packages(string id, string version)
=> this.View();
return this.View(new GallerySearchResultModel(count, this.PreparePackages(dbpackages.Skip(skip).Take(20), prerelease), next, skip - 20, query, prerelease));
}

[HttpGet, SlimGetRoute(Routing.GalleryAboutRouteName)]
public IActionResult About()
Expand All @@ -75,5 +136,87 @@ public IActionResult About()
this.PackageStorageConfiguration.SymbolsEnabled,
!this.PackageStorageConfiguration.ReadOnlyFeed));
}

private IEnumerable<GalleryPackageListItemModel> PreparePackages(IEnumerable<Package> dbpackages, bool prerelease = true)
{
foreach (var dbpackage in dbpackages)
{
var version = dbpackage.Versions
.Where(x => !x.IsPrerelase || prerelease)
.OrderByDescending(x => x.NuGetVersion)
.First();

yield return new GalleryPackageListItemModel
{
Id = dbpackage.Id,
Title = dbpackage.Title,
IconUrl = dbpackage.IconUrl,
Authors = dbpackage.AuthorNames,
Tags = dbpackage.TagNames,
DownloadCount = dbpackage.DownloadCount,
PublishedAt = dbpackage.PublishedAt.Value,
LastUpdatedAt = version.PublishedAt.Value,
LatestVersion = version.NuGetVersion,
Description = dbpackage.Description
};
}
}

private GalleryPackageInfoModel PreparePackage(Package dbpackage, PackageVersion dbversion)
=> new GalleryPackageInfoModel
{
Id = dbpackage.Id,
Title = dbpackage.Title,
IconUrl = dbpackage.IconUrl,
ProjectUrl = dbpackage.ProjectUrl,
LicenseUrl = dbpackage.LicenseUrl,
RepositoryUrl = dbpackage.RepositoryUrl,
Authors = dbpackage.AuthorNames,
Tags = dbpackage.TagNames,
DownloadCount = dbpackage.DownloadCount,
VersionDownloadCount = dbversion.DownloadCount,
PublishedAt = dbversion.PublishedAt.Value,
Version = dbversion.NuGetVersion,
Description = dbpackage.Description,
DownloadUrl = this.Url.AbsoluteUrl(Routing.DownloadPackageContentsRouteName, this.HttpContext, new
{
id = dbpackage.IdLowercase,
version = dbversion.VersionLowercase,
filename = $"{dbpackage.IdLowercase}.{dbversion.VersionLowercase}"
}),
ManifestUrl = this.Url.AbsoluteUrl(Routing.DownloadPackageManifestRouteName, this.HttpContext, new
{
id = dbpackage.IdLowercase,
version = dbversion.VersionLowercase,
id2 = dbpackage.IdLowercase
}),
// figure out symbols
DependencyGroups = this.PrepareDependencyGroups(dbversion),
OwnerId = dbpackage.OwnerId,
AllVersions = dbpackage.Versions.Select(x => (x.Version, x.DownloadCount, new DateTimeOffset(x.PublishedAt.Value)))
};

private IEnumerable<GalleryPackageDependencyGroupModel> PrepareDependencyGroups(PackageVersion dbversion)
{
foreach (var depgroup in dbversion.Dependencies.GroupBy(x => x.TargetFramework))
yield return new GalleryPackageDependencyGroupModel
{
Framework = NuGetFramework.Parse(depgroup.Key),
Dependencies = this.PrepareDependencies(depgroup)
};
}

private IEnumerable<GalleryPackageDependencyModel> PrepareDependencies(IEnumerable<PackageDependency> dbdeps)
{
foreach (var dbdep in dbdeps)
yield return new GalleryPackageDependencyModel
{
Id = dbdep.Id,
MinVersion = dbdep.MinVersion != null ? NuGetVersion.Parse(dbdep.MinVersion) : null,
MaxVersion = dbdep.MaxVersion != null ? NuGetVersion.Parse(dbdep.MaxVersion) : null,
MinInclusive = dbdep.IsMinVersionInclusive.HasValue && dbdep.IsMinVersionInclusive.HasValue,
MaxInclusive = dbdep.IsMaxVersionInclusive.HasValue && dbdep.IsMaxVersionInclusive.HasValue
};
}
}
}
2 changes: 1 addition & 1 deletion src/SlimGet/Controllers/IndexController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public IActionResult Index()
var registrationsBase = this.CreateResourceModels(this.Url.AbsoluteUrl(Routing.RegistrationsRouteName, this.HttpContext, new { mode = RegistrationsContentMode.Plain }).ToUri(), "RegistrationsBase", "", "3.0.0-beta", "3.0.0-rc");
var registrationsBaseGz = this.CreateResourceModels(this.Url.AbsoluteUrl(Routing.RegistrationsRouteName, this.HttpContext, new { mode = RegistrationsContentMode.GZip }).ToUri(), "RegistrationsBase", "3.4.0");
var registrationsBaseSemVer2 = this.CreateResourceModels(this.Url.AbsoluteUrl(Routing.RegistrationsRouteName, this.HttpContext, new { mode = RegistrationsContentMode.SemVer2 }).ToUri(), "RegistrationsBase", "3.6.0");
var packageDetailsUriTemplate = this.CreateResourceModels(this.Url.AbsoluteUrl(Routing.GalleryPackageVersionRouteName, this.HttpContext, new { id = "{id}", version = "{version}" }).Replace("%7B", "{").Replace("%7D", "}").ToUri(), "PackageDetailsUriTemplate", "5.1.0");
var packageDetailsUriTemplate = this.CreateResourceModels(this.Url.AbsoluteUrl(Routing.GalleryPackageRouteName, this.HttpContext, new { id = "{id}", version = "{version}" }).Replace("%7B", "{").Replace("%7D", "}").ToUri(), "PackageDetailsUriTemplate", "5.1.0");
var packageBaseAddress = this.CreateResourceModels(this.Url.AbsoluteUrl(Routing.DownloadPackageRouteName, this.HttpContext).ToUri(), "PackageBaseAddress", "3.0.0");

var resources = packagePublish
Expand Down
4 changes: 2 additions & 2 deletions src/SlimGet/Controllers/SearchController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public SearchController(SlimGetContext db, RedisService redis, IFileSystemServic
public async Task<IActionResult> Search([FromQuery] SearchQueryModel search, CancellationToken cancellationToken)
{
var semver2 = search.SemVerLevel == "2.0.0";
var prerelease = search.Prerelase;
var prerelease = search.Prerelease;
var query = search.Query;
var dbpackages = this.Database.Packages
.Include(x => x.Versions)
Expand All @@ -63,7 +63,7 @@ public async Task<IActionResult> Search([FromQuery] SearchQueryModel search, Can
public async Task<IActionResult> Autocomplete([FromQuery] SearchQueryModel search, CancellationToken cancellationToken)
{
var semver2 = search.SemVerLevel == "2.0.0";
var prerelease = search.Prerelase;
var prerelease = search.Prerelease;
if (search.Id == null)
{
var query = search.Query;
Expand Down
109 changes: 107 additions & 2 deletions src/SlimGet/Models/GalleryModels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,15 @@
// limitations under the License.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;
using NuGet.Frameworks;
using NuGet.Versioning;

namespace SlimGet.Models
{
public class GalleryAboutModel
public sealed class GalleryAboutModel
{
public Uri NuGetFeedUrl { get; }
public Uri SymbolsUrl { get; }
Expand All @@ -36,7 +41,7 @@ public GalleryAboutModel(Uri feedUrl, Uri symbolsUrl, Uri symbolsPushUrl, bool s
}
}

public class GalleryIndexModel
public sealed class GalleryIndexModel
{
public int PackageCount { get; }
public int VersionCount { get; }
Expand All @@ -47,4 +52,104 @@ public GalleryIndexModel(int pkgCount, int verCount)
this.VersionCount = verCount;
}
}

public sealed class GallerySearchModel
{
[FromQuery(Name = "q"), Display(Name = "Search query"), StringLength(32767, ErrorMessage = "Package ID query is too long.")]
public string Query { get; set; }

[FromQuery(Name = "skip"), Range(0, int.MaxValue, ErrorMessage = "Skip amount cannot be less than 0.")]
public int Skip { get; set; } = 0;

[FromQuery(Name = "pre"), Display(Name = "Include prerelease versions")]
public bool Prerelease { get; set; } = false;
}

public sealed class GalleryPackageListModel
{
public int TotalCount { get; }
public IEnumerable<GalleryPackageListItemModel> Items { get; }
public int NextPage { get; }
public int PreviousPage { get; }

public GalleryPackageListModel(int total, IEnumerable<GalleryPackageListItemModel> items, int next, int prev)
{
this.TotalCount = total;
this.Items = items;
this.NextPage = next;
this.PreviousPage = prev;
}
}

public sealed class GalleryPackageListItemModel
{
public string Id { get; set; }
public string Title { get; set; }
public string IconUrl { get; set; }
public IEnumerable<string> Authors { get; set; }
public IEnumerable<string> Tags { get; set; }
public long DownloadCount { get; set; }
public DateTimeOffset PublishedAt { get; set; }
public DateTimeOffset LastUpdatedAt { get; set; }
public NuGetVersion LatestVersion { get; set; }
public string Description { get; set; }
}

public sealed class GallerySearchResultModel
{
public int TotalCount { get; }
public IEnumerable<GalleryPackageListItemModel> Items { get; }
public int NextPage { get; }
public int PreviousPage { get; }
public string Query { get; }
public bool IncludePrerelease { get; }

public GallerySearchResultModel(int total, IEnumerable<GalleryPackageListItemModel> items, int next, int prev, string query, bool prerelease)
{
this.TotalCount = total;
this.Items = items;
this.NextPage = next;
this.PreviousPage = prev;
this.Query = query;
this.IncludePrerelease = prerelease;
}
}

public sealed class GalleryPackageInfoModel
{
public string Id { get; set; }
public string Title { get; set; }
public string IconUrl { get; set; }
public string ProjectUrl { get; set; }
public string LicenseUrl { get; set; }
public string RepositoryUrl { get; set; }
public IEnumerable<string> Authors { get; set; }
public IEnumerable<string> Tags { get; set; }
public long DownloadCount { get; set; }
public long VersionDownloadCount { get; set; }
public DateTimeOffset PublishedAt { get; set; }
public NuGetVersion Version { get; set; }
public string Description { get; set; }
public string DownloadUrl { get; set; }
public string ManifestUrl { get; set; }
//public string SymbolsUrl { get; set; }
public IEnumerable<GalleryPackageDependencyGroupModel> DependencyGroups { get; set; }
public string OwnerId { get; set; }
public IEnumerable<(string version, long downloads, DateTimeOffset publishedAt)> AllVersions { get; set; }
}

public sealed class GalleryPackageDependencyGroupModel
{
public NuGetFramework Framework { get; set; }
public IEnumerable<GalleryPackageDependencyModel> Dependencies { get; set; }
}

public sealed class GalleryPackageDependencyModel
{
public string Id { get; set; }
public NuGetVersion MinVersion { get; set; }
public NuGetVersion MaxVersion { get; set; }
public bool MinInclusive { get; set; }
public bool MaxInclusive { get; set; }
}
}
2 changes: 1 addition & 1 deletion src/SlimGet/Models/SearchQueryModels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public sealed class SearchQueryModel
public int Take { get; set; } = 20;

[FromQuery(Name = "prerelease")]
public bool Prerelase { get; set; } = false;
public bool Prerelease { get; set; } = false;

[FromQuery(Name = "semVerLevel")]
public string SemVerLevel { get; set; } = "2.0.0";
Expand Down
18 changes: 9 additions & 9 deletions src/SlimGet/Routing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ public static class Routing
public const string GalleryRoute = "/gallery";
public const string GalleryIndexRouteName = "Web,Gallery,Index";
public const string GalleryIndexRoute = "/";
public const string GalleryPackageIndexRouteName = "Web,Gallery,PackageIndex";
public const string GalleryPackageIndexRoute = "packages";
public const string GalleryPackageDetailsRouteName = "Web,Gallery,PackageDetails";
public const string GalleryPackageDetailsRoute = "packages/{id}";
public const string GalleryPackageVersionRouteName = "Web,Gallery,PackageVersion";
public const string GalleryPackageVersionRoute = "packages/{id}/{version}";
public const string GalleryListRouteName = "Web,Gallery,PackageList";
public const string GalleryListRoute = "packages";
public const string GalleryPackageRouteName = "Web,Gallery,Package";
public const string GalleryPackageRoute = "package/{id}/{version?}";
public const string GallerySearchRouteName = "Web,Gallery,PackageSearch";
public const string GallerySearchRoute = "search";
public const string GalleryAboutRouteName = "Web,Gallery,About";
public const string GalleryAboutRoute = "about";
// ENDOF: Gallery
Expand Down Expand Up @@ -145,9 +145,9 @@ public static class Routing
// BEGIN: Gallery
[GalleryRouteName] = GalleryRoute,
[GalleryIndexRouteName] = GalleryIndexRoute,
[GalleryPackageIndexRouteName] = GalleryPackageIndexRoute,
[GalleryPackageDetailsRouteName] = GalleryPackageDetailsRoute,
[GalleryPackageVersionRouteName] = GalleryPackageVersionRoute,
[GalleryListRouteName] = GalleryListRoute,
[GalleryPackageRouteName] = GalleryPackageRoute,
[GallerySearchRouteName] = GallerySearchRoute,
[GalleryAboutRouteName] = GalleryAboutRoute,
// ENDOF: Gallery

Expand Down
Loading

0 comments on commit c735cf7

Please sign in to comment.