net6
Paul Schneider 2 years ago
parent ca079e1c47
commit 6f79be26d8
33 changed files with 554 additions and 369 deletions

@ -1,6 +1,11 @@
# ISN
[![pipeline status](http://gitlab.pschneider.fr/Paul/nuget-host/badges/main/pipeline.svg)](http://gitlab.pschneider.fr/Paul/nuget-host/-/commits/main)
FIXME
````log
NU1301: Failed to retrieve information about 'xxx' from remote source 'https://isn.pschneider.fr/nupkg/xxx/index.json'.
````
## Usage
@ -29,7 +34,7 @@ dotnet publish -c Release
````bash
sudo mkdir -p /srv/www/isnd
sudo cp -a src/isnd/bin/Release/netcoreapp2.1/publish/* /srv/www/isnd
sudo cp -a src/isnd/bin/Release/net6.0/publish/* /srv/www/isnd
sudo cp contrib/isnd /etc/init.d/isnd
sudo chmod +x /etc/init.d/isnd
sudo chown -R www-data.www-data /srv/www/isnd
@ -55,7 +60,7 @@ sudo systemctl enable isnd
````bash
sudo mkdir /usr/local/lib/isn
sudo cp -a src/isn/bin/Release/netcoreapp2.1/* /usr/local/lib/isn
sudo cp -a src/isn/bin/Release/net6.0/* /usr/local/lib/isn
sudo chown -R root.root /usr/local/lib/isn
sudo ln -s /usr/local/lib/isn/isn /usr/local/bin/isn
````
@ -63,63 +68,15 @@ sudo ln -s /usr/local/lib/isn/isn /usr/local/bin/isn
### Mises à jour
````bash
set -e
# compiler tout
dotnet build -c Release
dotnet publish -c Release -f netcoreapp2.1 src/isnd
dotnet publish -c Release -f net6.0 src/isnd
# MAJ du serveur
sudo systemctl stop isnd
sudo cp -a src/isnd/bin/Release/netcoreapp2.1/publish/* /srv/www/isnd
sudo cp -a src/isnd/bin/Release/net6.0/publish/* /srv/www/isnd
sudo systemctl start isnd
# MAJ du client
sudo cp -a src/isn/bin/Release/netcoreapp2.1/* /usr/local/lib/isn
sudo cp -a src/isn/bin/Release/net6.0/* /usr/local/lib/isn
sudo chown -R root.root /usr/local/lib/isn
````
## TODO
```json
{
"@id": "https://api.nuget.org/v3/registration5-semver1/",
"@type": "RegistrationsBaseUrl",
"comment": "Base URL of Azure storage where NuGet package registration info is stored"
},
{
"@id": "https://api.nuget.org/v3-flatcontainer/",
"@type": "PackageBaseAddress/3.0.0",
"comment": "Base URL of where NuGet packages are stored, in the format https://api.nuget.org/v3-flatcontainer/{id-lower}/{version-lower}/{id-lower}.{version-lower}.nupkg"
},
{
"@id": "https://api.nuget.org/v3/registration5-semver1/",
"@type": "RegistrationsBaseUrl/3.0.0-rc",
"comment": "Base URL of Azure storage where NuGet package registration info is stored used by RC clients. This base URL does not include SemVer 2.0.0 packages."
},
{
"@id": "https://api.nuget.org/v3/registration5-semver1/",
"@type": "RegistrationsBaseUrl/3.0.0-beta",
"comment": "Base URL of Azure storage where NuGet package registration info is stored used by Beta clients. This base URL does not include SemVer 2.0.0 packages."
},
{
"@id": "https://www.nuget.org/packages/{id}/{version}?_src=template",
"@type": "PackageDetailsUriTemplate/5.1.0",
"comment": "URI template used by NuGet Client to construct details URL for packages"
},
{
"@id": "https://api.nuget.org/v3/registration5-gz-semver2/",
"@type": "RegistrationsBaseUrl/3.6.0",
"comment": "Base URL of Azure storage where NuGet package registration info is stored in GZIP format. This base URL includes SemVer 2.0.0 packages."
},
````

@ -1,9 +1,17 @@
using isnd.Data.Catalog;
using Newtonsoft.Json;
namespace isn.Abstract
{
public class ApiIndexViewModel
public class ApiIndexViewModel : HappyIdOwner
{
public ApiIndexViewModel(string id) : base(id)
{
}
[JsonProperty("@id")]
public string Id { get => GetId(); }
[JsonProperty("version")]
public string Version { get; set; }

@ -0,0 +1,35 @@
using Newtonsoft.Json;
namespace isnd.Data.Catalog
{
public class HappyIdOwner
{
public HappyIdOwner(string id)
{
this.id = id;
}
private string id;
public string GetId() { return id; }
public override bool Equals(object obj)
{
if (obj!=null)
{
if (GetType().IsAssignableFrom(obj.GetType()))
{
var rpobj = (HappyIdOwner) obj;
return this.id == rpobj.id;
}
}
return base.Equals(obj);
}
public override int GetHashCode()
{
return id.GetHashCode();
}
}
}

@ -1,9 +1,16 @@
using isnd.Data.Catalog;
using Newtonsoft.Json;
namespace isn.Abstract
{
public class Resource
public class Resource : HappyIdOwner
{
public Resource(string id, string typename) : base(id)
{
Type = typename;
Id = id;
}
[JsonProperty("@id")]
public string Id {get; set; }

@ -32,7 +32,7 @@ namespace isnd.Controllers
[HttpGet(_pkgRootPrefix + ApiConfig.IndexDotJson)]
public IActionResult ApiIndex()
{
return Ok(new ApiIndexViewModel{ Version = PackageManager.BASE_API_LEVEL, Resources = resources });
return Ok(new ApiIndexViewModel(packageManager.CatalogBaseUrl + ApiConfig.IndexDotJson){ Version = PackageManager.BASE_API_LEVEL, Resources = resources });
}
}

@ -1,3 +1,4 @@
using System.Data.Common;
using System.Linq;
using System.Threading.Tasks;
using isnd.Services;
@ -5,11 +6,14 @@ using isnd.Entities;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using NuGet.Versioning;
using isnd.Data.Packages.Catalog;
using isnd.Data.Catalog;
namespace isnd.Controllers
{
public partial class PackagesController
{
// https://docs.microsoft.com/en-us/nuget/api/catalog-resource#versioning
[HttpGet(_pkgRootPrefix + ApiConfig.Catalog)]
public async Task<IActionResult> CatalogIndex()
@ -33,51 +37,12 @@ namespace isnd.Controllers
// query.TotalHits = result.Items.Select(i=>i.Items.Length).Aggregate((a,b)=>a+b);
return Ok(index);
}
var leaf = packageManager.SearchById(id, lower, null);
if (leaf.Count() == 0) return NotFound(new { id, lower });
return Ok(leaf.First());
// return a Package
var leaf = await packageManager.GetCatalogLeafAsync(id, lower, null);
if (null == leaf) return NotFound(new { id, lower });
return Ok(leaf);
}
/// <summary>
/// Catalog Leaf,
/// Get info about given package id, and optional lower part .
/// </summary>
/// <param name="id">Given Package Id</param>
/// <param name="lower">lower part, a semantic version for the package,
/// and eventually followed by the "package type"</param>
/// <returns>Info about concerned packages, in order to be able and download them</returns>
[HttpGet(_pkgRootPrefix + ApiConfig.CatalogLeaf + "/{id}/{lower?}/index.json")]
public IActionResult CatalogLeaf(string id, string lower = null)
{
Data.PackageVersion[] pkgvs = null;
if (lower == "{lower}") lower = null;
bool askForindex = lower == null;
if (lower != null && lower.IndexOf('/') > 0 )
{
string version = lower.Substring(lower.IndexOf('/'));
pkgvs = this.packageManager.GetCatalogLeaf(id, version, lower).ToArray();
}
else {
pkgvs = this.packageManager.GetCatalogLeaf(id, null, lower).ToArray();
}
if (pkgvs.Count() == 0) return NotFound();
List<string> types = pkgvs.Select(
v => v.Type ?? "Dependency"
).Distinct().ToList();
if (!types.Contains("PackageDelete"))
types.Add("PackageDetails");
var last = pkgvs.Last();
var pub = last.LatestCommit.CommitTimeStamp;
return Ok(new Data.Packages.Catalog.CatalogLeaf
{
CommitId = last.CommitId,
Id = id,
CommitTimeStamp = pub,
Version = last.FullString,
Published = pub,
RefType = types.ToArray()
});
}
}
}

@ -1,19 +1,51 @@
using System.Net.Sockets;
using System.ComponentModel.DataAnnotations;
using Newtonsoft.Json;
using isnd.Data.Packages;
using NuGet.Versioning;
using System.Collections.Generic;
using System;
using isnd.Interfaces;
namespace isnd.Data.Catalog
{
public class CatalogEntry
public class CatalogEntry : HappyIdOwner , IObject// , IPackageDetails
{
/// <summary>
/// The URL to the document used to produce this object
/// Creates a catalog entry
/// </summary>
/// <param name="id">package details url</param>
/// <returns></returns>
public CatalogEntry(string id): base(id)
{
}
/// <summary>
/// The ID of the package
/// </summary>
/// <value></value>
[Key][Required,JsonRequired]
[StringLength(1024)]
[JsonProperty("@id")]
[JsonProperty("id")]
public string Id { get; set; }
/// <summary>
/// The Package details url
/// </summary>
/// <returns></returns>
[JsonProperty("@id")]
public string refid { get => GetId(); }
[JsonProperty("@type")]
public string[] RefType { get; set; }
[JsonProperty("commitId")]
public string CommitId { get; set; }
[JsonProperty("commitTimeStamp")]
public DateTime CommitTimeStamp { get; set; }
/// <summary>
/// Authors
/// </summary>
@ -35,12 +67,9 @@ namespace isnd.Data.Catalog
[JsonProperty("description")]
public string Description { get; set; }
public string iconUrl { get; set; }
public string language { get; set; }
/// <summary>
/// The ID of the package
/// </summary>
/// <value></value>
public string idp { get; set; }
public string licenseUrl { get; set; }
public string licenseExpression { get; set; }
/// <summary>
@ -51,11 +80,6 @@ namespace isnd.Data.Catalog
public string minClientVersion { get; set; }
public string projectUrl { get; set; }
/// <summary>
/// A string containing a ISO 8601 timestamp of when the package was published
/// </summary>
/// <value></value>
public string published { get; set; }
public bool requireLicenseAcceptance { get; set; }
public string summary { get; set; }
@ -66,17 +90,30 @@ namespace isnd.Data.Catalog
public string tags { get; set; }
public string title { get; set; }
/// <summary>
/// The full version string after normalization
/// The security vulnerabilities of the package
/// </summary>
/// <value></value>
[Required,JsonRequired]
public string version { get; set; } // string yes
public Vulnerabilitie[] vulnerabilities { get; set; }
public string packageContent { get; set; }
/// <summary>
/// The security vulnerabilities of the package
/// A string containing a ISO 8601 timestamp of when the package was published
/// </summary>
/// <value></value>
public Vulnerabilitie[] vulnerabilities { get; set; }
[JsonProperty("published")]
public DateTime Published { get; set; }
/// <summary>
/// The full version string after normalization
/// </summary>
/// <value></value>
[Required,JsonRequired]
[JsonProperty("version")]
public string Version { get; set; }
}
}

@ -7,34 +7,28 @@ using NuGet.Versioning;
namespace isnd.Data.Catalog
{
public class RegistrationPage
public class RegistrationPage : HappyIdOwner
{
[JsonProperty("@id")]
[JsonRequired]
public string Id { get; protected set;}
public string Id { get => GetId(); }
private readonly string pkgid;
private readonly List<PackageVersion> items;
protected string Bid { get ; private set; }
protected string DlBase { get; }
protected string ExternalUrl { get; }
public RegistrationPage (string bid, string dlBase)
public RegistrationPage (string bid, string pkgid, string extUrl) : base(bid + "/" + pkgid + "/index.json")
{
Bid = bid;
DlBase = dlBase;
Parent = Bid + $"/{pkgid}/index.json";
ExternalUrl = extUrl;
this.items = new List<PackageVersion>();
this.pkgid = pkgid;
}
public RegistrationPage (string bid, string pkgid, string dlBase, IEnumerable<PackageVersion> items)
public RegistrationPage(string bid, string pkgid, string extUrl, List<PackageVersion> versions) : this(bid, pkgid, extUrl)
{
Bid = bid;
Parent = Bid + $"/{pkgid}/index.json";
DlBase = dlBase;
this.items = new List<PackageVersion>();
this.Id = Bid + "/" + pkgid + "/index.json";
this.pkgid = pkgid;
AddVersionRange(items);
AddVersionRange(versions);
}
public string GetPackageId()
@ -43,12 +37,12 @@ namespace isnd.Data.Catalog
}
/// <summary>
/// no The array of registration leaves and their associate metadata
/// The array of registration leaves and their associate metadata
/// </summary>
/// <value></value>
[JsonProperty("items")]
public RegistrationLeaf[] Items { get => items.Select((p) => p.ToLeave(Bid, DlBase)).ToArray(); }
public CatalogEntry[] Items { get => items.Select((p) => p.ToLeave(Bid, ExternalUrl)).ToArray(); }
public void AddVersionRange(IEnumerable<PackageVersion> vitems)
{
@ -62,11 +56,15 @@ namespace isnd.Data.Catalog
long commitMax = 0;
foreach (var p in vitems)
{
if (items.Contains(p))
continue;
if (upper == null || upper < p.NugetVersion) upper = p.NugetVersion;
if (lower == null || lower > p.NugetVersion) lower = p.NugetVersion;
if (p.CommitNId> commitMax) commitMax = p.CommitNId;
if (items.Contains(p)) continue;
if (upper == null) upper = p.NugetVersion;
else if ( upper < p.NugetVersion) upper = p.NugetVersion;
if (lower == null) lower = p.NugetVersion;
else if (lower > p.NugetVersion) lower = p.NugetVersion;
if (p.CommitNId > commitMax) commitMax = p.CommitNId;
items.Add(p);
}
Upper = upper.ToFullString();

@ -1,26 +1,20 @@
using isnd.Data.Packages;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
namespace isnd.Data.Catalog
{
public class RegistrationPageIndex
public class RegistrationPageIndex : HappyIdOwner
{
/// <summary>
/// Page Url
/// </summary>
/// <value></value>
[JsonProperty("@id")]
[JsonRequired]
public string Id { get; protected set; }
public RegistrationPageIndex()
public RegistrationPageIndex(string url) : base(url)
{
Items = new List<RegistrationPage>();
}
public RegistrationPageIndex(string bid, string id, string dlBase, IEnumerable<Package> pkgs)
public RegistrationPageIndex(string bid, string id, string extUrl, IEnumerable<Package> pkgs) : base(bid + $"/{id}/index.json")
{
Items = new List<RegistrationPage>();
long cnid = 0;
@ -42,10 +36,9 @@ namespace isnd.Data.Catalog
}
}
}
Items.Add(new RegistrationPage(bid, gsp.Key, dlBase, versions));
Items.Add(new RegistrationPage(bid, gsp.Key, extUrl, versions));
}
CommitId = cnid.ToString();
Id = bid + $"/{id}/index.json";
}
[JsonProperty("count")]
@ -55,5 +48,6 @@ namespace isnd.Data.Catalog
public List<RegistrationPage> Items { get; set; }
public string CommitId { get; set; }
public DateTime CommitTimeStamp { get; internal set; }
}
}

@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
using isnd.Interfaces;
using Newtonsoft.Json;
namespace isnd.Data.Packages.Catalog
{
public class CatalogLeaf : IObject
{
[JsonProperty("@type")]
public string[] RefType { get; set; }
[JsonProperty("commitId")]
public string CommitId { get; set; }
[JsonProperty("commitTimeStamp")]
public DateTime CommitTimeStamp { get; set; }
[JsonProperty("published")]
public DateTime Published { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("version")]
public string Version { get; set; }
}
}

@ -4,7 +4,11 @@ using Newtonsoft.Json;
namespace isnd.Interfaces
{
public interface IObject
{
[JsonProperty("@type")]
public string Type { get => GetType().Name; }
[JsonProperty("commitId")]
string CommitId { get; }

@ -1,7 +0,0 @@
namespace isnd.Data.Packages.Catalog
{
public class PackageDetail : CatalogLeaf
{
}
}

@ -9,9 +9,24 @@ using Newtonsoft.Json;
namespace isnd.Data.Packages
{
public class Package : IObject
public interface IPackage
{
[Key][Required]
string Id { get; set; }
string OwnerId { get; set; }
string Description { get; set; }
bool Public { get; set; }
ApplicationUser Owner { get; set; }
List<PackageVersion> Versions { get; set; }
long CommitNId { get; set; }
string CommitId { get; }
Commit LatestVersion { get; set; }
DateTime CommitTimeStamp { get; set; }
}
public class Package : IObject, IPackage
{
[Key]
[Required]
[StringLength(1024)]
public string Id { get; set; }
@ -22,7 +37,7 @@ namespace isnd.Data.Packages
[StringLength(1024)]
public string Description { get; set; }
public bool Public { get ; set;}
public bool Public { get; set; }
[JsonIgnore]
virtual public ApplicationUser Owner { get; set; }
@ -36,15 +51,16 @@ namespace isnd.Data.Packages
/// or even deletion when no more active version.
/// </summary>
/// <value></value>
[Required][JsonIgnore]
public long CommitNId { get; set ; }
[Required]
[JsonIgnore]
public long CommitNId { get; set; }
[NotMapped]
public string CommitId { get => CommitNId.ToString(); }
[ForeignKey("CommitNId")]
public virtual Commit LatestVersion{ get; set; }
public virtual Commit LatestVersion { get; set; }
public DateTime CommitTimeStamp { get; set; }
}
}

@ -10,7 +10,9 @@ using NuGet.Versioning;
namespace isnd.Data
{
public class PackageVersion
public class PackageVersion
{
[Required]
[ForeignKey("Package")]
@ -20,10 +22,10 @@ namespace isnd.Data
[Required]
public int Major { get; set; }
[Required]
public int Minor { get; set; }
[Required]
public int Patch { get; set; }
@ -35,7 +37,8 @@ namespace isnd.Data
/// </summary>
/// <value></value>
[StringLength(256)]
[Required][Key]
[Required]
[Key]
public string FullString { get; set; }
public bool IsPrerelease { get; set; }
@ -45,7 +48,8 @@ namespace isnd.Data
[JsonIgnore]
public virtual Package Package { get; set; }
[Required][JsonIgnore]
[Required]
[JsonIgnore]
[ForeignKey("LatestCommit")]
public long CommitNId { get; set; }
@ -53,7 +57,7 @@ namespace isnd.Data
public string CommitId { get => CommitNId.ToString(); }
public virtual Commit LatestCommit {get; set; }
public virtual Commit LatestCommit { get; set; }
public string NugetLink => $"{Constants.PaquetFileEstension}/{PackageId}/{FullString}/{PackageId}-{FullString}."
+ Constants.PaquetFileEstension;
public string NuspecLink => $"{Constants.SpecFileEstension}/{PackageId}/{FullString}/{PackageId}-{FullString}."
@ -62,22 +66,15 @@ namespace isnd.Data
public string SementicVersionString { get => $"{Major}.{Minor}.{Patch}"; }
public NuGetVersion NugetVersion { get => new NuGetVersion(FullString); }
public RegistrationLeaf ToLeave(string bid, string dlbase)
public CatalogEntry ToLeave(string bid, string extUrl)
{
string leaveid = bid + "/" + this.PackageId + "/" + FullString + ".json";
return new RegistrationLeaf
return new CatalogEntry(bid + "/" + this.PackageId + "/" + FullString + ".json")
{
Id = leaveid,
PackageContent = dlbase + NugetLink,
Entry = new CatalogEntry
{
Id = leaveid,
idp = PackageId,
version = FullString,
authors = $"{this.Package.Owner.FullName} <${Package.Owner.Email}>"
}
Id = PackageId,
Version = FullString,
authors = $"{this.Package.Owner.FullName} <${Package.Owner.Email}>",
packageContent = extUrl + this.NugetLink
};
}
}
}

@ -24,8 +24,8 @@ namespace isnd.Interfaces
Task<PackageDeletionReport> DeletePackageAsync(string pkgid, string version, string type);
Task<PackageDeletionReport> UserAskForPackageDeletionAsync(string userid, string pkgId, string lower, string type);
Task<PackageVersion> GetPackageAsync(string pkgid, string version, string type);
IEnumerable<PackageVersion> GetCatalogLeaf(string pkgId, string version, string pkgType);
IEnumerable<RegistrationLeaf> SearchById(string pkgId, string semver, string pkgType);
Task<CatalogEntry> GetCatalogLeafAsync(string pkgId, string version, string pkgType);
IEnumerable<CatalogEntry> SearchById(string pkgId, string semver, string pkgType);
Task<RegistrationPageIndex> GetCatalogIndexAsync();
Task<RegistrationPageIndex> GetPackageRegistrationIndexAsync(RegistrationPageIndexQuery query);

@ -0,0 +1,85 @@
using System.Collections.Generic;
using System.Linq;
using isnd.Data.Catalog;
using Newtonsoft.Json.Serialization;
namespace isnd
{
internal class NSJWebApiReferenceResolver : IReferenceResolver
{
private int delautIdCounter;
Dictionary<string, HappyIdOwner> HappyIdOwners { get; set; }
Dictionary<int,object> Objects {get; set;}
internal NSJWebApiReferenceResolver()
{
delautIdCounter = 0;
HappyIdOwners = new Dictionary<string, HappyIdOwner>();
Objects = new Dictionary<int, object>();
}
public void AddReference(object context, string reference, object value)
{
if (value is HappyIdOwner)
{
string hoi = (value as HappyIdOwner).GetId();
if (HappyIdOwners.ContainsKey(hoi))
{
return;
}
HappyIdOwners[hoi] = value as HappyIdOwner;
}
else
{
if (Objects.ContainsValue(value))
{
return;
}
delautIdCounter++;
Objects[delautIdCounter] = value;
}
}
public string GetReference(object context, object value)
{
bool alreadyExists;
if (value is HappyIdOwner)
{
string oid = (value as HappyIdOwner).GetId();
if (oid == null)
throw new System.Exception("HappyIdOwner Id property is null");
if (HappyIdOwners.ContainsKey(oid))
{
alreadyExists=true;
return oid;
}
alreadyExists=false;
AddReference(context, oid, value);
return oid;
}
alreadyExists=false;
if (Objects.ContainsValue(value))
{
alreadyExists=true;
return Objects.First( ode => ode.Value ==value).Key.ToString();
}
alreadyExists=false;
delautIdCounter++;
Objects[delautIdCounter]=value;
return delautIdCounter.ToString();
}
public bool IsReferenced(object context, object value)
{
throw new System.NotImplementedException();
}
public object ResolveReference(object context, string reference)
{
throw new System.NotImplementedException();
}
}
}

@ -0,0 +1,12 @@
using System.Text.Json;
namespace isnd
{
internal class PreserveReferencesHandlingDictionaryKeyPolicy : JsonNamingPolicy
{
public override string ConvertName(string name)
{
throw new System.NotImplementedException();
}
}
}

@ -21,7 +21,7 @@ namespace isnd.Services
{
public class PackageManager : IPackageManager
{
public const string BASE_API_LEVEL = "3.5.0";
public const string BASE_API_LEVEL = "3.0.0";
ApplicationDbContext dbContext;
@ -36,86 +36,61 @@ namespace isnd.Services
public IEnumerable<Resource> GetResources(IUnleash unleashClient)
{
var res = new List<Resource>();
// stable
if (unleashClient.IsEnabled("pkg-push", true))
res.Add(
new Resource
{
Id = extUrl + ApiConfig.Publish,
Type = "PackagePublish/2.0.0",
Comment = "Package Publish service"
});
// under dev, only leash in release mode
if (unleashClient.IsEnabled("pkg-get", true))
res.Add(
new Resource
{
Id = extUrl + ApiConfig.GetPackage,
Type = "PackageBaseAddress/3.0.0",
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"
});
if (unleashClient.IsEnabled("pkg-autocomplete", false))
res.Add(
new Resource
{
Id = extUrl + ApiConfig.AutoComplete,
Type = "SearchAutocompleteService/" + BASE_API_LEVEL,
Comment = "Auto complete service"
});
if (unleashClient.IsEnabled("pkg-search", false))
res.Add(
new Resource
{
Id = extUrl + ApiConfig.Search,
Type = "SearchQueryService/" + BASE_API_LEVEL,
Comment = "Search Query service"
});
if (unleashClient.IsEnabled("pkg-catalog", true))
res.Add(
new Resource
{
Id = extUrl + ApiConfig.Catalog,
Type = "Catalog/" + BASE_API_LEVEL,
Comment = "Package Catalog Index"
});
res.Add(
new Resource
{
Id = extUrl + "v3.0.0/" + ApiConfig.Registration,
Type = "RegistrationsBaseUrl",
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-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
var res = new List<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."
});
new Resource(extUrl + ApiConfig.Publish, "PackagePublish/2.0.0")
{
Comment = "Package Publish service"
},
// under dev, only leash in release mode
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."
});
new Resource(extUrl + ApiConfig.GetPackage, "PackageBaseAddress/3.0.0")
{
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"
},
new Resource(extUrl + ApiConfig.AutoComplete, "SearchAutocompleteService/" + BASE_API_LEVEL)
{
Comment = "Auto complete service"
},
new Resource(extUrl + ApiConfig.Search,"SearchQueryService/" + BASE_API_LEVEL)
{
Comment = "Search Query service"
},
new Resource(extUrl + "versioned/" + ApiConfig.Registration, "RegistrationsBaseUrl/Versioned")
{
Comment = "Base URL of storage where isn package registration info is stored. This base URL includes SemVer 2.0.0 packages."
}
};
/* new Resource(extUrl + ApiConfig.Catalog, "Catalog/" + BASE_API_LEVEL)
{
Comment = "Package Catalog Index"
},*/
/* res.Add(
); res.Add(
new Resource(extUrl + "v3.0.0/" + ApiConfig.Registration, "RegistrationsBaseUrl")
{
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(extUrl + "v3.0.0-beta/" + ApiConfig.Registration, "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(extUrl + "v3.0.0-rc/" + ApiConfig.Registration,"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(extUrl + "v3.4.0/" + ApiConfig.Registration,"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(); */
return res;
}
@ -177,24 +152,15 @@ namespace isnd.Services
string baseid = extUrl + ApiConfig.Catalog;
string bidreg = $"{extUrl}v3.4.0/{ApiConfig.Registration}";
RegistrationPageIndex CurrentCatalogIndex = new RegistrationPageIndex();
RegistrationPageIndex index = new RegistrationPageIndex(baseid);
var scope = await dbContext.Commits.OrderBy(c => c.TimeStamp).ToArrayAsync();
RegistrationPage page = null;
i = isndSettings.CatalogPageLen;
foreach (var commit in scope)
{
if (i >= this.isndSettings.CatalogPageLen)
{
page = new RegistrationPage(bidreg, extUrl)
{
CommitId = commit.CommitId,
CommitTimeStamp = commit.CommitTimeStamp
};
CurrentCatalogIndex.Items.Add(page);
i = 0;
}
var validPkgs = (await dbContext.Packages
.Include(po => po.Owner)
.Include(pkg => pkg.Versions)
@ -204,10 +170,19 @@ namespace isnd.Services
// pkg.Versions.OrderByDescending(vi => vi.CommitNId).First().FullString
foreach (var pkgid in validPkgs)
{
StringBuilder refid = new(bidreg);
refid.AppendFormat("{0}/", pkgid.Key);
RegistrationPage page = index.Items.FirstOrDefault
(p => p.GetPackageId() == pkgid.Key);
if (page == null)
{
page = new RegistrationPage(bidreg, pkgid.Key, extUrl);
index.Items.Add(page);
}
foreach (var pkgv in pkgid)
{
page.AddVersionRange(pkgv.Versions);
}
}
reason = commit;
i++;
@ -215,14 +190,15 @@ namespace isnd.Services
if (reason != null)
{
CurrentCatalogIndex.CommitId = reason.CommitId;
index.CommitId = reason.CommitId;
index.CommitTimeStamp = reason.CommitTimeStamp;
}
else
{
// From a fresh db
CurrentCatalogIndex.CommitId = "none";
index.CommitId = "none";
}
return CurrentCatalogIndex;
return index;
}
public async Task<PackageDeletionReport> DeletePackageAsync(string pkgid, string version, string type)
@ -258,15 +234,15 @@ namespace isnd.Services
);
}
public IEnumerable<PackageVersion> GetCatalogLeaf(string pkgId, string semver = null, string pkgType = null)
public async Task<CatalogEntry> GetCatalogLeafAsync(string pkgId, string semver = null, string pkgType = null)
{
return dbContext.PackageVersions
return (await dbContext.PackageVersions
.Include(v => v.Package)
.Include(v => v.LatestCommit)
.Where(v => v.PackageId == pkgId
&& (semver == null ||
semver.StartsWith(v.SementicVersionString))
&& (pkgType == null || pkgType == v.Type));
&& semver == v.SementicVersionString
&& (pkgType == null || pkgType == v.Type)).SingleOrDefaultAsync()).ToLeave(BID,
extUrl);
}
public async Task<PackageDeletionReport> UserAskForPackageDeletionAsync(string uid, string id, string lower, string type)
@ -280,9 +256,11 @@ namespace isnd.Services
return new PackageDeletionReport { Deleted = true, DeletedVersion = packageVersion };
}
public IEnumerable<Data.Catalog.RegistrationLeaf> SearchById(string pkgId, string semver, string pkgType)
public string BID { get => $"{extUrl}v3.4.0/{ApiConfig.Registration}"; }
public IEnumerable<CatalogEntry> SearchById(string pkgId, string semver, string pkgType)
{
string bid = $"{extUrl}v3.4.0/{ApiConfig.Registration}";
return dbContext.PackageVersions
.Include(v => v.Package)
.Include(v => v.Package.Owner)
@ -290,7 +268,7 @@ namespace isnd.Services
.Where(v => v.PackageId == pkgId && semver == v.FullString
&& (pkgType == null || pkgType == v.Type))
.OrderByDescending(p => p.CommitNId)
.Select(p => p.ToLeave(bid, extUrl))
.Select(p => p.ToLeave(BID, extUrl))
;
}
public PackageVersion GetPackage(string pkgId, string semver, string pkgType)
@ -305,9 +283,11 @@ namespace isnd.Services
public async Task<RegistrationPageIndex> GetPackageRegistrationIndexAsync(RegistrationPageIndexQuery query)
{
// RegistrationPageIndexAndQuery
if (string.IsNullOrWhiteSpace(query.Query)) return null;
query.Query = query.Query.ToLower();
var scope = await dbContext.Packages.Include(p => p.Versions).Include(p => p.Owner)
.Where(p => MatchingExact(p, query)).Skip(query.Skip).Take(query.Take).ToListAsync();
.Where(p => p.Id.ToLower() == query.Query).Skip(query.Skip).Take(query.Take).ToListAsync();
string bid = $"{extUrl}v3.4.0/{ApiConfig.Registration}";
return
new RegistrationPageIndex(bid, query.Query, extUrl, scope);

@ -1,4 +1,6 @@
using Microsoft.AspNetCore.Builder;
using System.Linq;
using System.Collections.Generic;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
@ -22,9 +24,14 @@ using Microsoft.OpenApi.Models;
using System.IO;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using System.Text.Json;
using System.Text.Json.Serialization;
using isnd.Data.Catalog;
using Newtonsoft.Json;
namespace isnd
{
public class Startup
{
@ -97,8 +104,11 @@ namespace isnd
ValidateAudience = false
};
});
services.AddControllersWithViews();
services.AddControllersWithViews()
.AddNewtonsoftJson(s => {
s.SerializerSettings.ReferenceResolverProvider = () => new NSJWebApiReferenceResolver();
} );
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
@ -135,7 +145,6 @@ namespace isnd
app.UseMigrationsEndPoint();
app.UseSwagger();
app.UseSwaggerUI();
}
else
{
@ -145,7 +154,6 @@ namespace isnd
}
app.UseStatusCodePages().UseStaticFiles().UseAuthentication();
app.UseMvcWithDefaultRoute();
}
}
}

@ -9,25 +9,12 @@ namespace isnd.ViewModels
public string Id { get; set; }
/*
"@id": "https://api.nuget.org/v3/registration3/nuget.versioning/4.3.0.json",
"catalogEntry": "https://api.nuget.org/v3/catalog0/data/2017.08.11.18.24.22/nuget.versioning.4.3.0.json",
"listed": true,
"packageContent": "https://api.nuget.org/v3-flatcontainer/nuget.versioning/4.3.0/nuget.versioning.4.3.0.nupkg",
"published": "2017-08-11T18:24:14.36+00:00",
"registration": "https://api.nuget.org/v3/registration3/nuget.versioning/index.json"
*/
[JsonProperty("catalogEntry")]
public string CatalogEntry { get; set; }
[JsonProperty("listed")]
public bool Listed { get; set; } = true;
[JsonProperty("packageContent")]
public string PackageContent { get; set; }
[JsonProperty("published")]
public DateTime CommitTimeStamp { get; set; }

@ -10,10 +10,10 @@
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Result.Items[0].Items[0].Entry.idp)
@Html.DisplayNameFor(model => model.Result.Items[0].Items[0].refid)
</th>
<th>
@Html.DisplayNameFor(model => model.Result.Items[0].Items[0].Entry.Description)
@Html.DisplayNameFor(model => model.Result.Items[0].Items[0].Description)
</th>
<th></th>
</tr>

@ -0,0 +1,14 @@
using System.Text.Json;
namespace isnd
{
internal class TypeIdNamingPolicy : JsonNamingPolicy
{
public override string ConvertName(string name)
{
if (name == "Id") return "@id";
if (name == "Type") return "@type";
return "" + char.ToLower(name[0]) + name[1..];
}
}
}

@ -0,0 +1,98 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
using isnd.Data.Catalog;
namespace isnd
{
class WebApiReferenceHandler : ReferenceHandler
{
public WebApiReferenceHandler() => Reset();
private ReferenceResolver? _rootedResolver;
public override ReferenceResolver CreateResolver() => _rootedResolver!;
public void Reset() => _rootedResolver = new WebApiReferenceResolver();
}
public class WebApiReferenceResolver : ReferenceResolver
{
private int delautIdCounter;
Dictionary<string, HappyIdOwner> HappyIdOwners { get; set; }
Dictionary<int,object> Objects {get; set;}
public WebApiReferenceResolver()
{
delautIdCounter = 0;
HappyIdOwners = new Dictionary<string, HappyIdOwner>();
Objects = new Dictionary<int, object>();
}
public override void AddReference(string referenceId, object value)
{
if (value is HappyIdOwner)
{
string hoi = (value as HappyIdOwner).GetId();
if (HappyIdOwners.ContainsKey(hoi))
{
return;
}
HappyIdOwners[hoi] = value as HappyIdOwner;
}
else
{
if (Objects.ContainsValue(value))
{
return;
}
delautIdCounter++;
Objects[delautIdCounter] = value;
}
}
public override string GetReference(object value, out bool alreadyExists)
{
if (value is HappyIdOwner)
{
string oid = (value as HappyIdOwner).GetId();
if (oid == null)
throw new System.Exception("HappyIdOwner Id property is null");
if (HappyIdOwners.ContainsKey(oid))
{
alreadyExists=true;
return oid;
}
alreadyExists=false;
AddReference(oid, value);
return oid;
}
alreadyExists=false;
if (Objects.ContainsValue(value))
{
alreadyExists=true;
return Objects.First( ode => ode.Value ==value).Key.ToString();
}
alreadyExists=false;
delautIdCounter++;
Objects[delautIdCounter]=value;
return delautIdCounter.ToString();
}
public override object ResolveReference(string referenceId)
{
if (HappyIdOwners.ContainsKey(referenceId))
return HappyIdOwners[referenceId];
int refNId;
if (int.TryParse(referenceId, out refNId))
{
if (Objects.ContainsKey(refNId))
{
return Objects[refNId];
}
}
return null;
}
}
}

@ -37,6 +37,7 @@
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Antiforgery" Version="2.2.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.14" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../isn.abst/isn.abst.csproj" />

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<apikeys>
</apikeys>
<packageSources>
<add key="dev" value="http://localhost:5000/index.json" protocolVersion="3" />
<!-- <add key="isn-prod" value="https://isn.pschneider.fr/index.json" protocolVersion="3" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" /> -->
</packageSources>
</configuration>

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<apikeys>
</apikeys>
<packageSources>
<add key="isn-dev" value="http://localhost:5000/index.json" protocolVersion="3" />
</packageSources>
</configuration>

@ -1,4 +0,0 @@
#!/bin/bash
nuget locals all -clear && dotnet nuget locals all --clear && nuget add Yavsc.Abstract -Config NuGet.Config -Source isn-dev

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>test_isn</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

@ -0,0 +1,5 @@
#!/bin/bash
nuget locals all -clear && dotnet nuget locals all --clear && \
nuget install -NoCache -Verbosity detailed -ConfigFile ANuGet.Config Yavsc.Abstract

@ -1 +1 @@
nuget install -NoCache -Verbosity detailed -ConfigFile NuGet.Config Yavsc.Abstract
nuget install -NoCache -Verbosity detailed -ConfigFile ANuGet.Config Yavsc.Abstract

@ -9,12 +9,12 @@
<Version>1.0.7</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
<PackageReference Include="xunit.runner.reporters" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
<PackageToolReference Include="xunit.runner.console" Version="2.4.1" PrivateAssets="All" />
<PackageReference Include="xunit.runner.reporters" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.2" />
<PackageToolReference Include="xunit.runner.console" Version="2.4.2" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\isn\isn.csproj" />

@ -1,3 +1,4 @@
using System.Threading;
using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore;
@ -88,6 +89,21 @@ namespace isnd.host.tests
new Uri(isnSettings.ExternalUrl + "/v3.4.0//registration"));
}
}
[Fact]
public void TrueTestRegistrationV3Resource()
{
using (var serviceScope = server.Host.Services.CreateScope())
{
var isnSettings = serviceScope.ServiceProvider.GetService<IOptions<isnd.Entities.IsndSettings>>().Value;
string pkgSourceUrl = isnSettings.ExternalUrl + "/index.json";
var prov = new RegistrationResourceV3Provider();
var source = new PackageSource(pkgSourceUrl);
var repo = new SourceRepository(source, new INuGetResourceProvider[]{ prov });
prov.TryCreate(repo, CancellationToken.None);
}
}
private Task<HttpHandlerResource> PkgSourceMessageHandler()
{

@ -12,11 +12,11 @@
<ItemGroup>
<PackageReference Include="XunitXml.TestLogger" Version="3.0.70" />
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
<PackageReference Include="xunit.runner.reporters" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
<PackageReference Include="xunit.runner.reporters" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\isnd\isnd.csproj" />

Loading…