2021-09-05 15:44:47 +01:00
using System ;
2021-07-05 12:55:52 +01:00
using System.Collections.Generic ;
using System.Linq ;
2021-09-05 15:44:47 +01:00
using System.Text ;
using System.Threading.Tasks ;
2022-04-09 19:53:26 +01:00
using isn.Abstract ;
2021-08-15 19:09:01 +01:00
using isnd.Data ;
2022-08-20 12:54:24 +01:00
using isnd.Data.Catalog ;
2022-07-10 17:05:05 +01:00
using isnd.Data.Packages ;
using isnd.Data.Packages.Catalog ;
2021-08-23 03:21:08 +01:00
using isnd.Entities ;
2021-09-05 15:44:47 +01:00
using isnd.Helpers ;
2021-08-23 03:21:08 +01:00
using isnd.Interfaces ;
2021-08-11 23:25:15 +01:00
using isnd.ViewModels ;
2021-07-05 12:55:52 +01:00
using Microsoft.EntityFrameworkCore ;
2021-08-23 03:21:08 +01:00
using Microsoft.Extensions.Options ;
2021-07-05 12:55:52 +01:00
using NuGet.Versioning ;
using Unleash ;
namespace isnd.Services
{
2021-08-23 03:21:08 +01:00
public class PackageManager : IPackageManager
2021-07-05 12:55:52 +01:00
{
2022-04-17 14:10:20 +01:00
public const string BASE_API_LEVEL = "3.5.0" ;
2022-04-17 14:48:18 +01:00
2021-07-05 12:55:52 +01:00
ApplicationDbContext dbContext ;
2022-07-10 17:05:05 +01:00
2021-08-28 18:41:22 +01:00
public PackageManager ( ApplicationDbContext dbContext ,
2021-08-27 21:22:34 +01:00
IOptions < IsndSettings > siteConfigOptionsOptions )
2021-07-05 12:55:52 +01:00
{
this . dbContext = dbContext ;
2021-08-28 21:26:39 +01:00
isndSettings = siteConfigOptionsOptions . Value ;
2021-09-04 13:41:00 +01:00
extUrl = isndSettings . ExternalUrl + "/" ;
2021-07-05 12:55:52 +01:00
}
2021-08-23 03:21:08 +01:00
2021-09-02 23:37:28 +01:00
public IEnumerable < Resource > GetResources ( IUnleash unleashClient )
{
var res = new List < Resource > ( ) ;
// stable
if ( unleashClient . IsEnabled ( "pkg-push" , true ) )
res . Add (
new Resource
{
2021-09-08 01:55:00 +01:00
Id = extUrl + ApiConfig . Publish ,
2022-04-17 14:10:20 +01:00
Type = "PackagePublish/2.0.0" , // TODO BASE_API_LEVEL
2021-09-08 01:55:00 +01:00
Comment = "Package Publish service"
2021-09-02 23:37:28 +01:00
} ) ;
// under dev, only leash in release mode
2022-07-10 17:05:05 +01:00
if ( unleashClient . IsEnabled ( "pkg-get" , true ) )
2021-09-02 23:37:28 +01:00
res . Add (
new Resource
{
2022-07-03 14:50:57 +01:00
Id = extUrl + ApiConfig . GetPackage ,
2022-07-10 17:05:05 +01:00
Type = "PackageBaseAddress/3.0.0" ,
2023-02-06 21:43:18 +00:00
Comment = @"Package Base Address service - Base URL of where NuGet packages are stored, in the format https://<host>/nupkg/{id-lower}/{version-lower}/{id-lower}.{version-lower}.nupkg"
2021-09-02 23:37:28 +01:00
} ) ;
2023-02-06 21:43:18 +00:00
if ( unleashClient . IsEnabled ( "pkg-autocomplete" , false ) )
2021-09-02 23:37:28 +01:00
res . Add (
new Resource
{
2021-09-08 01:55:00 +01:00
Id = extUrl + ApiConfig . AutoComplete ,
2022-04-17 14:10:20 +01:00
Type = "SearchAutocompleteService/" + BASE_API_LEVEL ,
2021-09-08 01:55:00 +01:00
Comment = "Auto complete service"
2021-09-02 23:37:28 +01:00
} ) ;
2023-02-06 21:43:18 +00:00
if ( unleashClient . IsEnabled ( "pkg-search" , false ) )
2021-09-02 23:37:28 +01:00
res . Add (
new Resource
{
2021-09-08 01:55:00 +01:00
Id = extUrl + ApiConfig . Search ,
2022-04-17 14:10:20 +01:00
Type = "SearchQueryService/" + BASE_API_LEVEL ,
2021-09-08 01:55:00 +01:00
Comment = "Search Query service"
2021-09-02 23:37:28 +01:00
} ) ;
2023-02-06 21:43:18 +00:00
if ( unleashClient . IsEnabled ( "pkg-catalog" , false ) )
2021-09-05 15:44:47 +01:00
res . Add (
new Resource
{
2021-09-08 01:55:00 +01:00
Id = extUrl + ApiConfig . Catalog ,
2022-07-10 17:05:05 +01:00
Type = "Catalog/" + BASE_API_LEVEL ,
2021-09-08 01:55:00 +01:00
Comment = "Package Catalog Index"
2022-04-17 16:22:40 +01:00
} ) ;
2022-07-10 17:05:05 +01:00
/* FIXME */
res . Add (
2022-04-17 16:22:40 +01:00
new Resource
{
2023-02-06 21:43:18 +00:00
Id = extUrl + "v3.0.0/" + ApiConfig . Registration ,
2022-07-10 17:05:05 +01:00
Type = "RegistrationsBaseUrl" ,
2022-04-17 16:22:40 +01:00
Comment = "Base URL of storage where isn package registration info is stored in GZIP format. This base URL includes SemVer 2.0.0 packages."
2022-07-10 17:05:05 +01:00
} ) ;
res . Add (
new Resource
{
Id = extUrl + "v3.0.0-beta/" + ApiConfig . Registration ,
Type = "RegistrationsBaseUrl/3.0.0-beta" ,
Comment = "Base URL of storage where isn package registration info is stored in GZIP format. This base URL includes SemVer 2.0.0 packages."
} ) ;
res . Add (
new Resource
{
Id = extUrl + "v3.0.0-rc/" + ApiConfig . Registration ,
Type = "RegistrationsBaseUrl/3.0.0-rc" ,
Comment = "Base URL of storage where isn package registration info is stored in GZIP format. This base URL includes SemVer 2.0.0 packages."
} ) ;
res . Add ( new Resource
{
Id = extUrl + "v3.4.0/" + ApiConfig . Registration ,
Type = "RegistrationsBaseUrl/3.4.0" ,
Comment = "Base URL of storage where isn package registration info is stored in GZIP format. This base URL includes SemVer 2.0.0 packages."
} ) ;
res . Add ( new Resource
{
Id = extUrl + "v3.6.0/" + ApiConfig . Registration ,
Type = "RegistrationsBaseUrl/3.6.0" ,
Comment = "Base URL of storage where isn package registration info is stored in GZIP format. This base URL includes SemVer 2.0.0 packages."
} ) ;
2022-10-15 18:26:55 +01:00
2021-09-02 23:37:28 +01:00
return res ;
}
2021-08-23 03:21:08 +01:00
public AutoCompleteResult AutoComplete ( string id ,
int skip , int take , bool prerelease = false ,
2021-07-05 12:55:52 +01:00
string packageType = null )
{
var scope = dbContext . PackageVersions . Where (
v = > v . PackageId = = id
& & ( prerelease | | ! v . IsPrerelease )
& & ( packageType = = null | | v . Type = = packageType )
)
. OrderBy ( v = > v . FullString ) ;
return new AutoCompleteResult
2021-08-23 03:21:08 +01:00
{
totalHits = scope . Count ( ) ,
data = scope . Select ( v = > v . FullString )
2021-07-05 12:55:52 +01:00
. Skip ( skip ) . Take ( take ) . ToArray ( )
2021-08-23 03:21:08 +01:00
} ;
2021-07-05 12:55:52 +01:00
}
// TODO stocker MetaData plutôt que FullString en base,
// et en profiter pour corriger ce listing
public string [ ] GetVersions (
string id ,
NuGetVersion parsedVersion ,
bool prerelease = false ,
string packageType = null ,
int skip = 0 ,
int take = 25 )
{
return dbContext . PackageVersions . Where (
v = > v . PackageId = = id
& & ( prerelease | | ! v . IsPrerelease )
& & ( packageType = = null | | v . Type = = packageType )
& & ( parsedVersion . CompareTo ( new SemanticVersion ( v . Major , v . Minor , v . Patch ) ) < 0 )
)
2022-09-27 00:39:17 +01:00
. OrderBy ( v = > v . NugetVersion )
2021-07-05 12:55:52 +01:00
. Select ( v = > v . FullString )
. Skip ( skip ) . Take ( take ) . ToArray ( ) ;
}
2023-02-06 21:43:18 +00:00
2022-09-23 20:34:51 +01:00
public string CatalogBaseUrl = > extUrl ;
2021-08-28 21:26:39 +01:00
private IsndSettings isndSettings ;
2021-09-02 23:37:28 +01:00
private string extUrl ;
2021-08-23 03:21:08 +01:00
2023-02-06 21:43:18 +00:00
public virtual async Task < RegistrationPageIndex > GetCatalogIndexAsync ( )
2021-08-23 03:21:08 +01:00
{
2023-02-06 21:43:18 +00:00
return await Û pdateCatalogForAsync ( null ) ;
2021-08-23 03:21:08 +01:00
}
2023-02-06 21:43:18 +00:00
public async Task < RegistrationPageIndex > Û pdateCatalogForAsync ( Commit reason = null )
2021-08-23 03:21:08 +01:00
{
2021-08-28 18:41:22 +01:00
int i = 0 ;
2023-02-06 21:43:18 +00:00
2022-07-10 17:05:05 +01:00
string baseid = extUrl + ApiConfig . Catalog ;
2022-10-15 18:26:55 +01:00
string bidreg = $"{extUrl}v3.4.0/{ApiConfig.Registration}" ;
2022-07-10 17:05:05 +01:00
string basepageid = extUrl + ApiConfig . CatalogPage ;
2023-02-06 21:43:18 +00:00
RegistrationPageIndex CurrentCatalogIndex = new RegistrationPageIndex ( ) ;
List < RegistrationPage > CurrentCatalogPages = new List < RegistrationPage > ( ) ;
2021-08-27 21:22:34 +01:00
var scope = dbContext . Commits . OrderBy ( c = > c . TimeStamp ) ;
2022-07-10 17:05:05 +01:00
2022-09-25 02:24:21 +01:00
RegistrationPage page = null ;
2021-08-28 21:26:39 +01:00
i = isndSettings . CatalogPageLen ;
2021-08-27 21:22:34 +01:00
foreach ( var commit in scope )
{
2021-08-28 21:26:39 +01:00
if ( i > = this . isndSettings . CatalogPageLen )
2021-08-27 21:22:34 +01:00
{
2022-10-15 18:26:55 +01:00
page = new RegistrationPage ( basepageid , extUrl )
2021-08-28 18:41:22 +01:00
{
2021-08-27 21:22:34 +01:00
CommitId = commit . CommitId ,
2022-09-25 02:24:21 +01:00
CommitTimeStamp = commit . CommitTimeStamp
2021-08-27 21:22:34 +01:00
} ;
CurrentCatalogPages . Add ( page ) ;
2022-10-15 18:26:55 +01:00
var pageRef = new RegistrationPage ( page . Id , extUrl )
2021-08-28 18:41:22 +01:00
{
2021-09-05 15:44:47 +01:00
CommitId = commit . CommitId ,
CommitTimeStamp = commit . CommitTimeStamp
2021-08-27 21:22:34 +01:00
} ;
CurrentCatalogIndex . Items . Add ( pageRef ) ;
i = 0 ;
}
2023-02-06 21:43:18 +00:00
var validPkgs = dbContext . Packages
2022-09-27 00:39:17 +01:00
. Include ( po = > po . Owner )
2021-08-28 18:41:22 +01:00
. Include ( pkg = > pkg . Versions )
2021-08-29 00:08:34 +01:00
. Include ( pkg = > pkg . LatestVersion )
2023-02-06 21:43:18 +00:00
. ToList ( )
. GroupBy ( ( q ) = > q . Id ) ;
2021-08-28 18:41:22 +01:00
// pkg.Versions.OrderByDescending(vi => vi.CommitNId).First().FullString
2022-09-25 02:24:21 +01:00
foreach ( var pkgid in validPkgs )
2021-08-27 21:22:34 +01:00
{
2022-09-25 02:24:21 +01:00
StringBuilder refid = new StringBuilder ( bidreg ) ;
refid . AppendFormat ( "{0}/" ,
pkgid . Key ) ;
2022-10-15 18:26:55 +01:00
/ * var pkgref = new PackageRef
{
Version = v . FullString ,
LastCommit = v . LatestCommit ,
CommitId = v . LatestCommit . CommitId ,
CommitTimeStamp = v . LatestCommit . CommitTimeStamp ,
RefId = refid . ToString ( ) ,
Id = v . PackageId ,
RefType = v . LatestCommit . Action = = PackageAction . PublishPackage
? "nuget:PackageDetails" :
"nuget:PackageDelete"
} ; * /
foreach ( var pkgv in pkgid )
page . AddVersionRange ( pkgv . Versions ) ;
2021-08-28 18:41:22 +01:00
}
2021-09-05 15:44:47 +01:00
reason = commit ;
2021-08-27 21:22:34 +01:00
i + + ;
}
2021-09-05 15:44:47 +01:00
if ( reason ! = null )
2021-08-27 21:22:34 +01:00
{
2021-09-05 15:44:47 +01:00
CurrentCatalogIndex . CommitId = reason . CommitId ;
2021-08-27 21:22:34 +01:00
}
2021-09-05 15:44:47 +01:00
else
2021-08-28 18:41:22 +01:00
{
2021-09-05 15:44:47 +01:00
// From a fresh db
2021-08-28 18:41:22 +01:00
CurrentCatalogIndex . CommitId = "none" ;
}
2023-02-06 21:43:18 +00:00
return CurrentCatalogIndex ;
2021-08-23 03:21:08 +01:00
}
2021-09-05 18:55:38 +01:00
public async Task < PackageDeletionReport > DeletePackageAsync ( string pkgid , string version , string type )
2021-07-05 12:55:52 +01:00
{
2022-07-03 14:50:57 +01:00
// TODO deletion on disk
2022-07-10 17:05:05 +01:00
var commit = new Commit
{
2021-09-05 15:44:47 +01:00
Action = PackageAction . DeletePackage ,
TimeStamp = DateTime . Now
} ;
2021-09-05 17:10:50 +01:00
dbContext . Commits . Add ( commit ) ;
2021-09-05 15:44:47 +01:00
var pkg = await dbContext . PackageVersions . SingleOrDefaultAsync (
2021-09-05 18:55:38 +01:00
v = > v . PackageId = = pkgid & &
v . FullString = = version & &
v . Type = = type
2021-09-05 15:44:47 +01:00
) ;
if ( pkg = = null )
2021-07-05 12:55:52 +01:00
{
2022-07-10 17:05:05 +01:00
return new PackageDeletionReport { Deleted = false } ;
2021-07-05 12:55:52 +01:00
}
2021-09-05 15:44:47 +01:00
dbContext . PackageVersions . Remove ( pkg ) ;
await dbContext . SaveChangesAsync ( ) ;
2023-02-06 21:43:18 +00:00
await Û pdateCatalogForAsync ( commit ) ;
2022-07-10 17:05:05 +01:00
return new PackageDeletionReport { Deleted = true , DeletedVersion = pkg } ;
2021-07-05 12:55:52 +01:00
}
2021-09-05 18:55:38 +01:00
public async Task < PackageVersion > GetPackageAsync ( string pkgid , string version , string type )
{
return await dbContext . PackageVersions . SingleOrDefaultAsync (
v = > v . PackageId = = pkgid & &
v . FullString = = version & &
v . Type = = type
) ;
}
2022-09-23 20:34:51 +01:00
2022-12-17 01:29:22 +00:00
public IEnumerable < PackageVersion > GetCatalogLeaf ( string pkgId , string semver = null , string pkgType = null )
2022-07-03 14:50:57 +01:00
{
return dbContext . PackageVersions
2022-07-10 17:05:05 +01:00
. Include ( v = > v . Package )
2022-07-29 09:06:59 +01:00
. Include ( v = > v . LatestCommit )
2022-10-15 18:26:55 +01:00
. Where ( v = > v . PackageId = = pkgId
& & ( semver = = null | |
2022-09-24 12:32:00 +01:00
semver . StartsWith ( v . SementicVersionString ) )
& & ( pkgType = = null | | pkgType = = v . Type ) ) ;
2022-07-03 14:50:57 +01:00
}
2022-09-23 20:34:51 +01:00
public async Task < PackageDeletionReport > UserAskForPackageDeletionAsync ( string uid , string id , string lower , string type )
{
PackageVersion packageVersion = await dbContext . PackageVersions
. Include ( pv = > pv . Package )
. FirstOrDefaultAsync ( m = > m . PackageId = = id
& & m . FullString = = lower & & m . Type = = type ) ;
if ( packageVersion = = null ) return null ;
if ( packageVersion . Package . OwnerId ! = uid ) return null ;
return new PackageDeletionReport { Deleted = true , DeletedVersion = packageVersion } ;
}
2022-09-24 12:32:00 +01:00
public IEnumerable < Data . Catalog . RegistrationLeaf > SearchById ( string pkgId , string semver , string pkgType )
{
2022-10-15 18:26:55 +01:00
string bid = $"{extUrl}v3.4.0/{ApiConfig.Registration}" ;
2022-09-24 12:32:00 +01:00
return dbContext . PackageVersions
. Include ( v = > v . Package )
2022-09-27 00:39:17 +01:00
. Include ( v = > v . Package . Owner )
2022-09-24 12:32:00 +01:00
. Include ( v = > v . LatestCommit )
2022-10-17 19:17:04 +01:00
. Where ( v = > v . PackageId . Equals ( pkgId , StringComparison . InvariantCultureIgnoreCase ) & & semver . Equals ( v . FullString , StringComparison . InvariantCultureIgnoreCase )
2022-10-15 18:26:55 +01:00
& & ( pkgType = = null | | pkgType = = v . Type ) )
2022-10-17 19:17:04 +01:00
. OrderByDescending ( p = > p . CommitNId )
. Select ( p = > p . ToLeave ( bid , extUrl ) )
2022-10-15 18:26:55 +01:00
;
2022-09-24 12:32:00 +01:00
}
public PackageVersion GetPackage ( string pkgId , string semver , string pkgType )
{
return dbContext . PackageVersions
. Include ( v = > v . Package )
. Include ( v = > v . LatestCommit )
. Single ( v = > v . PackageId = = pkgId & & semver = = v . FullString
& & ( pkgType = = null | | pkgType = = v . Type ) ) ;
}
2022-09-27 00:39:17 +01:00
2023-02-06 21:43:18 +00:00
public async Task < RegistrationPageIndex > GetPackageRegistrationIndexAsync ( RegistrationPageIndexQuery query )
2022-09-27 00:39:17 +01:00
{
// RegistrationPageIndexAndQuery
2023-02-06 21:43:18 +00:00
var scope = ( await dbContext . Packages . Include ( p = > p . Versions ) . Include ( p = > p . Owner )
. ToListAsync ( ) ) . Where ( p = > MatchingExact ( p , query ) ) ;
2022-09-27 00:39:17 +01:00
var total = scope . Count ( ) ;
var pkgs = scope . Skip ( query . Skip ) . Take ( query . Take ) . ToArray ( ) ;
2022-10-15 18:26:55 +01:00
string bid = $"{extUrl}v3.4.0/{ApiConfig.Registration}" ;
return
new RegistrationPageIndex ( bid , query . Query , extUrl , pkgs ) ;
2022-09-27 00:39:17 +01:00
}
2023-01-29 13:04:50 +00:00
public async Task < RegistrationPageIndex > SearchPackageAsync ( RegistrationPageIndexQuery query )
2022-10-17 19:17:04 +01:00
{
string bid = $"{extUrl}v3.4.0/{ApiConfig.Registration}" ;
2023-02-06 21:43:18 +00:00
2022-10-17 19:17:04 +01:00
if ( query . Query = = null ) query . Query = "" ;
2023-02-06 21:43:18 +00:00
var scope = ( await dbContext . Packages . Include ( p = > p . Versions ) . Include ( p = > p . Owner )
. ToListAsync ( ) )
. Where ( p = > Matching ( p , query ) )
;
var total = scope . Count ( ) ;
var pkgs = scope . Skip ( query . Skip ) . Take ( query . Take ) ;
2022-10-17 19:17:04 +01:00
return
new RegistrationPageIndex ( bid , query . Query , extUrl , pkgs ) ;
}
2023-02-06 21:43:18 +00:00
private static bool MatchingExact ( Package p , RegistrationPageIndexQuery query )
{
return
p . Id . Equals ( query . Query , StringComparison . InvariantCultureIgnoreCase )
& & ( query . Prerelease | | p . Versions . Any ( v = > ! v . IsPrerelease ) ) ;
}
private static bool Matching ( Package p , RegistrationPageIndexQuery query )
{
return p . Id . StartsWith ( query . Query , StringComparison . InvariantCultureIgnoreCase )
& & ( query . Prerelease | | p . Versions . Any ( v = > ! v . IsPrerelease ) ) ;
}
2021-07-05 12:55:52 +01:00
}
}