using System.ComponentModel.DataAnnotations; using System.IO; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using NuGet.Versioning; using isnd.Data; using isnd.Entities; using Unleash; using isnd.Services; using isnd.ViewModels; using System.Threading.Tasks; using isnd.Interfaces; namespace isnd.Controllers { [AllowAnonymous] public partial class PackagesController : Controller { const int maxTake = 100; const string _pkgRootPrefix = "~/package"; const string defaultSemVer = "2.0.0"; private readonly Resource[] _ressources; private readonly ILogger _logger; private readonly IDataProtector _protector; private readonly IsndSettings _isndSettings; readonly ApplicationDbContext _dbContext; private readonly IPackageManager _packageManager; private readonly IUnleash _unleashĈlient; public PackagesController( ILoggerFactory loggerFactory, IDataProtectionProvider provider, IOptions isndOptions, IUnleash unleashĈlient, ApplicationDbContext dbContext, IPackageManager pm) { _logger = loggerFactory.CreateLogger(); _isndSettings = isndOptions.Value; _protector = provider.CreateProtector(_isndSettings.ProtectionTitle); _dbContext = dbContext; _packageManager = pm; _unleashĈlient = unleashĈlient; _ressources = _packageManager.GetResources(_unleashĈlient).ToArray(); } // dotnet add . package -s http://localhost:5000/packages isn // packages/FindPackagesById()?id='isn'&semVerLevel=2.0.0 // Search // GET {@id}?q={QUERY}&skip={SKIP}&take={TAKE}&prerelease={PRERELEASE}&semVerLevel={SEMVERLEVEL}&packageType={PACKAGETYPE} // GET: PackageVersion public async Task Index(PackageIndexViewModel model) { var applicationDbContext = _dbContext.Packages.Include(p => p.Versions).Where( p => ( model.Prerelease || p.Versions.Any(v => !v.IsPrerelease)) && ((model.query == null) || p.Id.StartsWith(model.query))); model.data = await applicationDbContext.ToArrayAsync(); return View(model); } // GET: PackageVersion/Details/5 public async Task Details(string pkgid) { if (pkgid == null) { return NotFound(); } var packageVersion = _dbContext.PackageVersions .Include(p => p.Package) .Where(m => m.PackageId == pkgid) .OrderByDescending(p => p) ; if (packageVersion == null) { return NotFound(); } bool results = await packageVersion.AnyAsync(); var latest = await packageVersion.FirstAsync(); return View("Details", new PackageDetailViewModel { latest = latest, pkgid = pkgid, totalHits = packageVersion.Count(), data = packageVersion.Take(10).ToArray() } ); } [HttpGet("~/index.json")] public IActionResult ApiIndex() { return Ok(_ressources); } // [HttpGet(_pkgRootPrefix)] public IActionResult Index() { // https://docs.microsoft.com/en-us/nuget/api/catalog-resource#versioning return Ok(PackageManager.CurrentCatalogIndex); } // GET /autocomplete?id=isn.protocol&prerelease=true [HttpGet(_pkgRootPrefix + "/autocomplete")] public IActionResult AutoComplete( string id, string semVerLevel, bool prerelease = false, string packageType = null, int skip = 0, int take = 25) { if (take > maxTake) { ModelState.AddModelError("take", "Maximum exceeded"); return BadRequest(ModelState); } if (semVerLevel != defaultSemVer) { ModelState.AddModelError("semVerLevel", defaultSemVer + " expected"); } return Ok(_packageManager.AutoComplete(id,skip,take,prerelease,packageType)); } // TODO GET {@id}/{LOWER_ID}/index.json // LOWER_ID URL string yes The package ID, lowercased // response : versions array of strings yes The versions available [HttpGet(_pkgRootPrefix + "/{id}/{lower}/index.json")] public IActionResult GetVersions( string id, string lower, bool prerelease = false, string packageType = null, int skip = 0, int take = 25) { if (take > maxTake) { ModelState.AddModelError("take", "Maximum exceeded"); } // NugetVersion if (!NuGetVersion.TryParse(lower, out NuGetVersion parsedVersion)) { ModelState.AddModelError("lower", "invalid version string"); } if (!ModelState.IsValid) { return BadRequest(ModelState); } return Ok(new { versions = _packageManager.GetVersions( id, parsedVersion, prerelease, packageType, skip, take) }); } // TODO GET GET {@id}/{LOWER_ID}/{LOWER_VERSION}/{LOWER_ID}.{LOWER_VERSION}.nupkg // LOWER_ID URL string yes The package ID, lowercase // LOWER_VERSION URL string yes The package version, normalized and lowercased // response 200 : the package [HttpGet(_pkgRootPrefix + "/{id}/{lower}/{idf}-{lowerf}.nupkg")] public IActionResult GetPackage( [FromRoute] string id, [FromRoute] string lower, [FromRoute] string idf, [FromRoute] string lowerf) { var pkgpath = Path.Combine(_isndSettings.PackagesRootDir, id, lower, $"{id}-{lower}.nupkg" ); FileInfo pkgfi = new FileInfo(pkgpath); if (!pkgfi.Exists) { return BadRequest("!pkgfi.Exists"); } return File(pkgfi.OpenRead(), "application/zip; charset=binary"); } // TODO GET {@id}/{LOWER_ID}/{LOWER_VERSION}/{LOWER_ID}.nuspec // response 200 : the nuspec [HttpGet(_pkgRootPrefix + "/{id}/{lower}/{idf}-{lowerf}.nuspec")] public IActionResult GetNuspec( [FromRoute][SafeName][Required] string id, [FromRoute][SafeName][Required] string lower, [FromRoute][SafeName][Required] string idf, [FromRoute][SafeName][Required] string lowerf) { var pkgpath = Path.Combine(_isndSettings.PackagesRootDir, id, lower, $"{id}.nuspec"); FileInfo pkgfi = new FileInfo(pkgpath); if (!pkgfi.Exists) { return BadRequest("!pkgfi.Exists"); } return File(pkgfi.OpenRead(), "text/xml; charset=utf-8"); } } }