Compare commits
38 Commits
fixed-page
...
main
@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<project name="Isn" default="clean" basedir=".">
|
||||||
|
<description>The Hello World of build files.</description>
|
||||||
|
<property name="debug" value="true" overwrite="false" />
|
||||||
|
|
||||||
|
<target name="clean" description="remove all generated files">
|
||||||
|
<delete dir="src/isn.abst/bin/" failonerror="false" />
|
||||||
|
<delete dir="src/isn.abst/obj/" failonerror="false" />
|
||||||
|
<delete dir="src/isn/bin/" failonerror="false" />
|
||||||
|
<delete dir="src/isn/obj/" failonerror="false" />
|
||||||
|
<delete dir="src/isnd/bin/" failonerror="false" />
|
||||||
|
<delete dir="src/isnd/obj/" failonerror="false" />
|
||||||
|
<delete dir="test/isn.tests/bin/" failonerror="false" />
|
||||||
|
<delete dir="test/isn.tests/obj/" failonerror="false" />
|
||||||
|
<delete dir="test/isnd.tests/bin/" failonerror="false" />
|
||||||
|
<delete dir="test/isnd.tests/obj/" failonerror="false" />
|
||||||
|
</target>
|
||||||
|
<target name="build" description="build all">
|
||||||
|
<exec program="dotnet" commandline="build" />
|
||||||
|
</target>
|
||||||
|
<target name="test" description="test all">
|
||||||
|
<exec program="dotnet" commandline="test" />
|
||||||
|
</target>
|
||||||
|
</project>
|
@ -1,3 +1,21 @@
|
|||||||
/packages/
|
.sass-cache/
|
||||||
/bin/
|
/src/isnd/bin/
|
||||||
/obj/
|
/src/isnd/obj/
|
||||||
|
/src/isn/obj
|
||||||
|
/src/isn/bin
|
||||||
|
/src/isn/.vscode/
|
||||||
|
/test/isnd.tests/obj/
|
||||||
|
/test/isnd.tests/bin/
|
||||||
|
/test/isn.tests/bin
|
||||||
|
/test/isn.tests/obj/
|
||||||
|
/src/isn.abst/bin
|
||||||
|
/src/isn.abst/obj
|
||||||
|
/src/isnd/packages/
|
||||||
|
/test/data/test-isn/bin/
|
||||||
|
/test/data/test-isn/obj
|
||||||
|
.fake
|
||||||
|
/artifacts/
|
||||||
|
/.vs/
|
||||||
|
/.vscode/
|
||||||
|
appsettings.Development.json
|
||||||
|
|
||||||
|
@ -0,0 +1,66 @@
|
|||||||
|
# You can override the included template(s) by including variable overrides
|
||||||
|
# See https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings
|
||||||
|
# Note that environment variables can be set in several places
|
||||||
|
# See https://docs.gitlab.com/ee/ci/variables/#priority-of-environment-variables
|
||||||
|
image: busybox:latest
|
||||||
|
before_script:
|
||||||
|
- dotnet restore
|
||||||
|
- dotnet nuget remove source gitlab || true
|
||||||
|
nonreg:
|
||||||
|
tags:
|
||||||
|
- dotnet
|
||||||
|
stage: test
|
||||||
|
environment: Development
|
||||||
|
script:
|
||||||
|
- |
|
||||||
|
echo "setting : $ISND_TESTING_SETTINGS"
|
||||||
|
dotnet build
|
||||||
|
cat $ISND_TESTING_SETTINGS > test/isnd.tests/appsettings.json
|
||||||
|
dotnet test
|
||||||
|
publish:
|
||||||
|
tags:
|
||||||
|
- dotnet
|
||||||
|
stage: deploy
|
||||||
|
dependencies:
|
||||||
|
- nonreg
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- src/isnd/bin/Release/netcoreapp2.1/publish/
|
||||||
|
when: always
|
||||||
|
script:
|
||||||
|
- dotnet publish --configuration Release
|
||||||
|
deploy-to-gitlab:
|
||||||
|
tags:
|
||||||
|
- dotnet
|
||||||
|
stage: deploy
|
||||||
|
dependencies:
|
||||||
|
- nonreg
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- src/*/bin/Release/*.nupkg
|
||||||
|
when: always
|
||||||
|
script:
|
||||||
|
- dotnet pack -c Release
|
||||||
|
- dotnet nuget add source --name gitlab --username gitlab+deploy-token-2 --password
|
||||||
|
$CI_JOB_TOKEN --store-password-in-clear-text "$CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/packages/nuget/index.json"
|
||||||
|
- dotnet nuget push src/*/bin/Release/*.nupkg -s gitlab
|
||||||
|
deploy-to-isn:
|
||||||
|
stage: deploy
|
||||||
|
tags:
|
||||||
|
- dotnet
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- src/*/bin/Release/*.nupkg
|
||||||
|
when: always
|
||||||
|
script:
|
||||||
|
- dotnet pack --configuration Release --no-restore
|
||||||
|
- cd src/isn
|
||||||
|
- find -name "*.nupkg" -exec dotnet run push -s $ISNSOURCE -k $ISNAPIKEY {} \;
|
||||||
|
environment:
|
||||||
|
name: production
|
||||||
|
url: $ISNSOURCE
|
||||||
|
dependencies:
|
||||||
|
- nonreg
|
||||||
|
stages:
|
||||||
|
- test
|
||||||
|
- deploy
|
@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
// Use IntelliSense to learn about possible attributes.
|
|
||||||
// Hover to view descriptions of existing attributes.
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": ".NET Core Launch (web)",
|
|
||||||
"type": "coreclr",
|
|
||||||
"request": "launch",
|
|
||||||
"preLaunchTask": "build",
|
|
||||||
"program": "${workspaceFolder}/bin/Debug/netcoreapp2.0/nuget-host.dll",
|
|
||||||
"args": [],
|
|
||||||
"cwd": "${workspaceFolder}",
|
|
||||||
"stopAtEntry": false,
|
|
||||||
"OS-COMMENT5": "Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser",
|
|
||||||
"serverReadyAction": {
|
|
||||||
"action": "openExternally",
|
|
||||||
"pattern": "\\\\bNow listening on:\\\\s+(https?://\\\\S+)"
|
|
||||||
},
|
|
||||||
"env": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
},
|
|
||||||
"sourceFileMap": {
|
|
||||||
"/Views": "${workspaceFolder}/Views"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,113 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.IO.Compression;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using NuGet.Packaging;
|
|
||||||
|
|
||||||
namespace nuget_host.Controllers
|
|
||||||
{
|
|
||||||
public class PackagesController : Controller
|
|
||||||
{
|
|
||||||
private ILogger<PackagesController> logger;
|
|
||||||
|
|
||||||
public PackagesController(ILoggerFactory loggerFactory)
|
|
||||||
{
|
|
||||||
logger = loggerFactory.CreateLogger<PackagesController>();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPut("packages/{*spec}")]
|
|
||||||
public IActionResult Put(string spec)
|
|
||||||
{
|
|
||||||
string path = null;
|
|
||||||
if (string.IsNullOrEmpty(spec))
|
|
||||||
{
|
|
||||||
var clientVersionId = Request.Headers["X-NuGet-Client-Version"];
|
|
||||||
ViewData["nuget client "] = "nuget {clientVersionId}";
|
|
||||||
foreach (var file in Request.Form.Files)
|
|
||||||
{
|
|
||||||
string initpath = "package.nupkg";
|
|
||||||
using (FileStream fw = new FileStream(initpath, FileMode.Create))
|
|
||||||
{
|
|
||||||
file.CopyTo(fw);
|
|
||||||
}
|
|
||||||
|
|
||||||
using (FileStream fw = new FileStream(initpath, FileMode.Open))
|
|
||||||
{
|
|
||||||
var archive = new System.IO.Compression.ZipArchive(fw);
|
|
||||||
foreach (var filename in archive.GetFiles())
|
|
||||||
{
|
|
||||||
if (filename.EndsWith(".nuspec"))
|
|
||||||
{
|
|
||||||
// var entry = archive.GetEntry(filename);
|
|
||||||
var specstr = archive.OpenFile(filename);
|
|
||||||
NuspecReader reader = new NuspecReader(specstr);
|
|
||||||
|
|
||||||
string pkgdesc = reader.GetDescription();
|
|
||||||
string pkgid = reader.GetId();
|
|
||||||
var version = reader.GetVersion();
|
|
||||||
|
|
||||||
|
|
||||||
path = Path.Combine(Startup.SourceDir,
|
|
||||||
Path.Combine(pkgid,
|
|
||||||
Path.Combine(version.ToFullString(),
|
|
||||||
$"{pkgid}-{version}.nupkg")));
|
|
||||||
var source = new FileInfo(initpath);
|
|
||||||
var dest = new FileInfo(path);
|
|
||||||
var destdir = new DirectoryInfo(dest.DirectoryName);
|
|
||||||
if (dest.Exists)
|
|
||||||
return BadRequest(new {error = "existant"});
|
|
||||||
|
|
||||||
if (!destdir.Exists) destdir.Create();
|
|
||||||
source.MoveTo(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ViewData["spec"] = spec;
|
|
||||||
// TODO Assert valid sem ver spec
|
|
||||||
var filelst = new DirectoryInfo(Startup.SourceDir);
|
|
||||||
var fi = new FileInfo(spec);
|
|
||||||
var lst = filelst.GetFiles(fi.Name + "*.nupkg");
|
|
||||||
ViewData["lst"] = lst.Select(entry => entry.Name);
|
|
||||||
}
|
|
||||||
return Ok(ViewData);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("Packages/{spec}")]
|
|
||||||
public IActionResult Index(string spec)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(spec))
|
|
||||||
{
|
|
||||||
ViewData["warn"] = "no spec";
|
|
||||||
/*
|
|
||||||
usr/lib/mono/msbuild/Current/bin/NuGet.targets(128,5): error : Failed to retrieve information about 'Microsoft.VisualStudio.Web.CodeGeneration.Tools' from remote source 'http://localhost:5000/Packages/FindPackagesById()?id='Microsoft.VisualStudio.Web.CodeGeneration.Tools'&semVerLevel=2.0.0'. [/home/paul/workspace/nuget-host/nuget-host.csproj]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ViewData["spec"] = spec;
|
|
||||||
// TODO Assert valid sem ver spec
|
|
||||||
var filelst = new DirectoryInfo(Startup.SourceDir);
|
|
||||||
var fi = new FileInfo(spec);
|
|
||||||
var lst = filelst.GetDirectories(spec);
|
|
||||||
ViewData["lst"] = lst.Select(entry => entry.Name);
|
|
||||||
}
|
|
||||||
return Ok(ViewData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,5 @@
|
|||||||
|
mode: Mainline
|
||||||
|
branches: {}
|
||||||
|
ignore:
|
||||||
|
sha: []
|
||||||
|
merge-message-formats: {}
|
@ -0,0 +1,14 @@
|
|||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
Version 2, December 2004
|
||||||
|
|
||||||
|
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim or modified
|
||||||
|
copies of this license document, and changing it is allowed as long
|
||||||
|
as the name is changed.
|
||||||
|
|
||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||||
|
|
@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
CONFIGURATION=Debug
|
||||||
|
TARGETFV=net7.0
|
||||||
|
|
||||||
|
all: build-isn build-isnd
|
||||||
|
|
||||||
|
build-%: src/%
|
||||||
|
dotnet build -p:Configuration=$(CONFIGURATION) $^
|
||||||
|
|
||||||
|
pack-%: src/%
|
||||||
|
dotnet pack $^
|
||||||
|
|
||||||
|
watch:
|
||||||
|
dotnet watch --project=src/isnd
|
||||||
|
|
||||||
|
test-push:
|
||||||
|
isn push src/isn/bin/Debug/isn.*.nupkg
|
||||||
|
|
||||||
|
clean-%: src/%
|
||||||
|
rm -rf $^/bin $^/obj
|
||||||
|
|
||||||
|
packs: pack-isn pack-isnd pack-isn.abst
|
||||||
|
|
||||||
|
clean: clean-isnd clean-isn clean-isn.abst
|
||||||
|
|
||||||
|
TARGETFRAMEWORK=net8.0
|
||||||
|
|
||||||
|
server-update:
|
||||||
|
dotnet build -c Release src/isnd
|
||||||
|
dotnet publish -c Release -f $(TARGETFRAMEWORK) src/isnd
|
||||||
|
sudo systemctl stop isnd
|
||||||
|
sudo cp -a src/isnd/bin/Release/$(TARGETFRAMEWORK)/publish/* /srv/www/isnd
|
||||||
|
sudo systemctl start isnd
|
||||||
|
|
||||||
|
client-update:
|
||||||
|
dotnet build -c Release src/isn
|
||||||
|
# MAJ du client
|
||||||
|
sudo cp -a src/isn/bin/Release/$(TARGETFRAMEWORK)/* /usr/local/lib/isn
|
||||||
|
sudo chown -R root:root /usr/local/lib/isn
|
||||||
|
|
||||||
|
src/isn.abst/bin/Release/isn.abst.1.0.24.nupkg:
|
||||||
|
dotnet pack src/isn.abst -c Release
|
||||||
|
|
||||||
|
push-test: src/isn.abst/bin/Release/isn.abst.1.0.24.nupkg
|
||||||
|
isn push -s "http://localhost:3002/v3/index.json" src/isn.abst/bin/Release/isn.abst.1.0.24.nupkg
|
||||||
|
|
@ -1,11 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace nuget_host.Models
|
|
||||||
{
|
|
||||||
public class ErrorViewModel
|
|
||||||
{
|
|
||||||
public string RequestId { get; set; }
|
|
||||||
|
|
||||||
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +1,100 @@
|
|||||||
# Usage
|
# ISN
|
||||||
|
|
||||||
|
En cours de developement, le détail du paquet n'est toujours pas fourni en API.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
````sh
|
````sh
|
||||||
|
|
||||||
nuget sources remove -Name dev
|
dotnet user-secrets set ConnectionStrings:DefaultConnection "Server=<lame-pgserver>;Port=<lame-pgport>;Database=<lame-dbname>;Username=<lame-dbusername>;Password=<lame-dbpass>;"
|
||||||
nuget sources add -Name dev -Source Http://localhost:5000/packages
|
|
||||||
nuget push your-versionned.nupkg -ApiKey 15d0dda1-4028-4896-9f1a-188817da23f4 -Source http://localhost:5000/packages
|
isnd&
|
||||||
|
|
||||||
|
# get an api-key from <http://localhost:5000/ApkKeys>
|
||||||
|
|
||||||
|
isn push -k <lame-api-key> -s http://localhost:5000/index.json your-lame-versionned.nupkg
|
||||||
|
wget http://localhost:5000/package/index.json?q=your&prerelease=true&semVerLevel=2.0.0
|
||||||
|
````
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Compilation
|
||||||
|
|
||||||
|
Dans le dossier de la solution, compiler la solution :
|
||||||
|
|
||||||
|
````bash
|
||||||
|
dotnet build /restore -c Release
|
||||||
|
dotnet publish -c Release src/isnd
|
||||||
|
````
|
||||||
|
|
||||||
|
### Déploiement du serveur
|
||||||
|
|
||||||
|
La livraison initiale, aujourd'hui :
|
||||||
|
|
||||||
|
````bash
|
||||||
|
sudo mkdir -p /srv/www/isnd
|
||||||
|
sudo cp -a src/isnd/bin/Release/net8.0/publish/* /srv/www/isnd
|
||||||
|
sudo cp contrib/isnd.service /etc/systemd/system
|
||||||
|
chown -R isn:isn /srv/www/isnd/
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
````
|
||||||
|
|
||||||
|
Une base de donées Postgresql est requise, avec, pour faire simple,
|
||||||
|
son utilisateur, et le droit de créer des tables (ce dernier droit pourrait expirer, mais gare aux mises à jour).
|
||||||
|
|
||||||
|
Il faudra éditer la configuration pour indiquer :
|
||||||
|
|
||||||
|
* dans /etc/systemd/system/isnd.service , la connextion à une base de donnée Postresgql, sous la forme :
|
||||||
|
`"Server=<pgserver>;Port=<pgport>;Database=<dbname>;Username=<dbusername>;Password=<dbpass>;"`
|
||||||
|
* dans /srv/www/isnd/appsettings.Production.json, la connection au serveur de messagerie,
|
||||||
|
* l'URL externe du ou des sites à propulser, et à utiliser dans la description de service,
|
||||||
|
* et les autres détails.
|
||||||
|
|
||||||
|
Pour faire ceci, vous pourrez éditer une copie du fichier `appsettings.json` vers `appsettings.Production.json`,
|
||||||
|
pour renseigner toutes les valeurs spécifiées.
|
||||||
|
|
||||||
|
* Démarrer le serveur :
|
||||||
|
|
||||||
|
````bash
|
||||||
|
sudo systemctl start isnd
|
||||||
|
````
|
||||||
|
|
||||||
|
* Activation du serveur :
|
||||||
|
|
||||||
|
````bash
|
||||||
|
sudo systemctl enable isnd
|
||||||
|
````
|
||||||
|
|
||||||
|
### Installation du client
|
||||||
|
|
||||||
|
````bash
|
||||||
|
sudo mkdir /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
|
||||||
|
````
|
||||||
|
|
||||||
|
### Mises à jour
|
||||||
|
|
||||||
|
Dans le détail, la séquence serait du style :
|
||||||
|
|
||||||
|
````bash
|
||||||
|
# compiler tout
|
||||||
|
dotnet build -c Release
|
||||||
|
dotnet publish -c Release -f net8.0 src/isnd
|
||||||
|
# MAJ du serveur
|
||||||
|
sudo systemctl stop isnd
|
||||||
|
sudo cp -a src/isnd/bin/Release/net8.0/publish/* /srv/www/isnd
|
||||||
|
sudo systemctl start isnd
|
||||||
|
# MAJ du client
|
||||||
|
sudo cp -a src/isn/bin/Release/net8.0/* /usr/local/lib/isn
|
||||||
|
sudo chown -R root:root /usr/local/lib/isn
|
||||||
|
````
|
||||||
|
|
||||||
|
On pourra cibler "client-update" ou "server-update", à la construction :
|
||||||
|
|
||||||
|
|
||||||
|
````bash
|
||||||
|
make server-update
|
||||||
|
make client-update
|
||||||
````
|
````
|
||||||
|
@ -1,106 +0,0 @@
|
|||||||
@{
|
|
||||||
ViewData["Title"] = "Home Page";
|
|
||||||
}
|
|
||||||
|
|
||||||
<div id="myCarousel" class="carousel slide" data-ride="carousel" data-interval="6000">
|
|
||||||
<ol class="carousel-indicators">
|
|
||||||
<li data-target="#myCarousel" data-slide-to="0" class="active"></li>
|
|
||||||
<li data-target="#myCarousel" data-slide-to="1"></li>
|
|
||||||
<li data-target="#myCarousel" data-slide-to="2"></li>
|
|
||||||
<li data-target="#myCarousel" data-slide-to="3"></li>
|
|
||||||
</ol>
|
|
||||||
<div class="carousel-inner" role="listbox">
|
|
||||||
<div class="item active">
|
|
||||||
<img src="~/images/banner1.svg" alt="ASP.NET" class="img-responsive" />
|
|
||||||
<div class="carousel-caption" role="option">
|
|
||||||
<p>
|
|
||||||
Learn how to build ASP.NET apps that can run anywhere.
|
|
||||||
<a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkID=525028&clcid=0x409">
|
|
||||||
Learn More
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="item">
|
|
||||||
<img src="~/images/banner2.svg" alt="Visual Studio" class="img-responsive" />
|
|
||||||
<div class="carousel-caption" role="option">
|
|
||||||
<p>
|
|
||||||
There are powerful new features in Visual Studio for building modern web apps.
|
|
||||||
<a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkID=525030&clcid=0x409">
|
|
||||||
Learn More
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="item">
|
|
||||||
<img src="~/images/banner3.svg" alt="Package Management" class="img-responsive" />
|
|
||||||
<div class="carousel-caption" role="option">
|
|
||||||
<p>
|
|
||||||
Bring in libraries from NuGet and npm, and automate tasks using Grunt or Gulp.
|
|
||||||
<a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkID=525029&clcid=0x409">
|
|
||||||
Learn More
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="item">
|
|
||||||
<img src="~/images/banner4.svg" alt="Microsoft Azure" class="img-responsive" />
|
|
||||||
<div class="carousel-caption" role="option">
|
|
||||||
<p>
|
|
||||||
Learn how Microsoft's Azure cloud platform allows you to build, deploy, and scale web apps.
|
|
||||||
<a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkID=525027&clcid=0x409">
|
|
||||||
Learn More
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev">
|
|
||||||
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
|
|
||||||
<span class="sr-only">Previous</span>
|
|
||||||
</a>
|
|
||||||
<a class="right carousel-control" href="#myCarousel" role="button" data-slide="next">
|
|
||||||
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
|
|
||||||
<span class="sr-only">Next</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-3">
|
|
||||||
<h2>Application uses</h2>
|
|
||||||
<ul>
|
|
||||||
<li>Sample pages using ASP.NET Core MVC</li>
|
|
||||||
<li>Theming using <a href="https://go.microsoft.com/fwlink/?LinkID=398939">Bootstrap</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<h2>How to</h2>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://go.microsoft.com/fwlink/?LinkID=398600">Add a Controller and View</a></li>
|
|
||||||
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699315">Manage User Secrets using Secret Manager.</a></li>
|
|
||||||
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699316">Use logging to log a message.</a></li>
|
|
||||||
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699317">Add packages using NuGet.</a></li>
|
|
||||||
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699319">Target development, staging or production environment.</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<h2>Overview</h2>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://go.microsoft.com/fwlink/?LinkId=518008">Conceptual overview of what is ASP.NET Core</a></li>
|
|
||||||
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699320">Fundamentals of ASP.NET Core such as Startup and middleware.</a></li>
|
|
||||||
<li><a href="https://go.microsoft.com/fwlink/?LinkId=398602">Working with Data</a></li>
|
|
||||||
<li><a href="https://go.microsoft.com/fwlink/?LinkId=398603">Security</a></li>
|
|
||||||
<li><a href="https://go.microsoft.com/fwlink/?LinkID=699321">Client side development</a></li>
|
|
||||||
<li><a href="https://go.microsoft.com/fwlink/?LinkID=699322">Develop on different platforms</a></li>
|
|
||||||
<li><a href="https://go.microsoft.com/fwlink/?LinkID=699323">Read more on the documentation site</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<h2>Run & Deploy</h2>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://go.microsoft.com/fwlink/?LinkID=517851">Run your app</a></li>
|
|
||||||
<li><a href="https://go.microsoft.com/fwlink/?LinkID=517853">Run tools such as EF migrations and more</a></li>
|
|
||||||
<li><a href="https://go.microsoft.com/fwlink/?LinkID=398609">Publish to Microsoft Azure Web Apps</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,22 +0,0 @@
|
|||||||
@model ErrorViewModel
|
|
||||||
@{
|
|
||||||
ViewData["Title"] = "Error";
|
|
||||||
}
|
|
||||||
|
|
||||||
<h1 class="text-danger">Error.</h1>
|
|
||||||
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
|
||||||
|
|
||||||
@if (Model.ShowRequestId)
|
|
||||||
{
|
|
||||||
<p>
|
|
||||||
<strong>Request ID:</strong> <code>@Model.RequestId</code>
|
|
||||||
</p>
|
|
||||||
}
|
|
||||||
|
|
||||||
<h3>Development Mode</h3>
|
|
||||||
<p>
|
|
||||||
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Development environment should not be enabled in deployed applications</strong>, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>, and restarting the application.
|
|
||||||
</p>
|
|
@ -1,71 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>@ViewData["Title"] - nuget_host</title>
|
|
||||||
|
|
||||||
<environment include="Development">
|
|
||||||
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
|
|
||||||
<link rel="stylesheet" href="~/css/site.css" />
|
|
||||||
</environment>
|
|
||||||
<environment exclude="Development">
|
|
||||||
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
|
|
||||||
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
|
|
||||||
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
|
|
||||||
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
|
|
||||||
</environment>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<nav class="navbar navbar-inverse navbar-fixed-top">
|
|
||||||
<div class="container">
|
|
||||||
<div class="navbar-header">
|
|
||||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
|
||||||
<span class="sr-only">Toggle navigation</span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
</button>
|
|
||||||
<a asp-area="" asp-controller="Home" asp-action="Index" class="navbar-brand">nuget_host</a>
|
|
||||||
</div>
|
|
||||||
<div class="navbar-collapse collapse">
|
|
||||||
<ul class="nav navbar-nav">
|
|
||||||
<li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
|
|
||||||
<li><a asp-area="" asp-controller="Home" asp-action="About">About</a></li>
|
|
||||||
<li><a asp-area="" asp-controller="Home" asp-action="Contact">Contact</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<div class="container body-content">
|
|
||||||
@RenderBody()
|
|
||||||
<hr />
|
|
||||||
<footer>
|
|
||||||
<p>© 2018 - nuget_host</p>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<environment include="Development">
|
|
||||||
<script src="~/lib/jquery/dist/jquery.js"></script>
|
|
||||||
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
|
|
||||||
<script src="~/js/site.js" asp-append-version="true"></script>
|
|
||||||
</environment>
|
|
||||||
<environment exclude="Development">
|
|
||||||
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"
|
|
||||||
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
|
|
||||||
asp-fallback-test="window.jQuery"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
integrity="sha384-K+ctZQ+LL8q6tP7I94W+qzQsfRV2a+AfHIi9k8z8l9ggpc8X+Ytst4yBo/hH+8Fk">
|
|
||||||
</script>
|
|
||||||
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js"
|
|
||||||
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
|
|
||||||
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa">
|
|
||||||
</script>
|
|
||||||
<script src="~/js/site.min.js" asp-append-version="true"></script>
|
|
||||||
</environment>
|
|
||||||
|
|
||||||
@RenderSection("Scripts", required: false)
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,3 +0,0 @@
|
|||||||
@using nuget_host
|
|
||||||
@using nuget_host.Models
|
|
||||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
|
@ -0,0 +1,28 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=isnd - a Nuget package repository daemon
|
||||||
|
After=syslog.target
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
Wants=postgresql.service
|
||||||
|
After=postgresql.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
RestartSec=5s
|
||||||
|
Type=simple
|
||||||
|
User=isn
|
||||||
|
Group=isn
|
||||||
|
WorkingDirectory=/srv/www/isnd/
|
||||||
|
ExecStart=/srv/www/isnd/isnd
|
||||||
|
Restart=always
|
||||||
|
Environment="HOME=/srv/www/isnd"
|
||||||
|
Environment="ASPNETCORE_ENVIRONMENT=Production"
|
||||||
|
Environment="ASPNETCORE_ConnectionStrings__DefaultConnection=Server=localhost;Port=5432;Database=isnd;Username=paul;Password=RvJa=y#b/tfg;"
|
||||||
|
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||||
|
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||||
|
StandardOutput=syslog
|
||||||
|
StandardError=syslog
|
||||||
|
SyslogIdentifier=isnd
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<apikeys>
|
||||||
|
</apikeys>
|
||||||
|
<packageSources>
|
||||||
|
<add key="myIsnDev" value="http://localhost:5000/index.json" protocolVersion="3" />
|
||||||
|
</packageSources>
|
||||||
|
</configuration>
|
@ -0,0 +1,2 @@
|
|||||||
|
nuget install -Verbosity detailed -Source http://localhost:5000/index.json -Prerelease Yavsc.Abstract
|
||||||
|
nuget locals all -clear
|
@ -0,0 +1,4 @@
|
|||||||
|
= URL's
|
||||||
|
|
||||||
|
<http://localhost:5000/v3.4.0/registration/yavsc.abstract/index.json>
|
||||||
|
|
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"isRoot": true,
|
||||||
|
"tools": {
|
||||||
|
"codecov.tool": {
|
||||||
|
"version": "1.13.0",
|
||||||
|
"commands": [
|
||||||
|
"codecov"
|
||||||
|
],
|
||||||
|
"rollForward": false
|
||||||
|
},
|
||||||
|
"gitversion.tool": {
|
||||||
|
"version": "5.10.1",
|
||||||
|
"commands": [
|
||||||
|
"dotnet-gitversion"
|
||||||
|
],
|
||||||
|
"rollForward": false
|
||||||
|
},
|
||||||
|
"gitreleasemanager.tool": {
|
||||||
|
"version": "0.13.0",
|
||||||
|
"commands": [
|
||||||
|
"dotnet-gitreleasemanager"
|
||||||
|
],
|
||||||
|
"rollForward": false
|
||||||
|
},
|
||||||
|
"Wyam2.Tool": {
|
||||||
|
"version": "3.0.0-rc3",
|
||||||
|
"commands": [
|
||||||
|
"wyam2"
|
||||||
|
],
|
||||||
|
"rollForward": false
|
||||||
|
},
|
||||||
|
"dotnet-ef": {
|
||||||
|
"version": "8.0.7",
|
||||||
|
"commands": [
|
||||||
|
"dotnet-ef"
|
||||||
|
],
|
||||||
|
"rollForward": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
drop table "AspNetRoleClaims" ;
|
||||||
|
drop table "AspNetUserRoles" ;
|
||||||
|
drop table "AspNetRoles" ;
|
||||||
|
drop table "AspNetUserClaims" ;
|
||||||
|
drop table "AspNetUserTokens" ;
|
||||||
|
drop table "PackageVersions" ;
|
||||||
|
drop table "Packages" ;
|
||||||
|
drop table "Commits" ;
|
||||||
|
drop table "ApiKeys" ;
|
||||||
|
drop table "AspNetUserLogins" ;
|
||||||
|
drop table "AspNetUsers" ;
|
||||||
|
drop table "__EFMigrationsHistory" ;
|
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"dotnet": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"msbuild": {
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
|
"Dnx": {
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
|
"Script": {
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
|
"fileOptions": {
|
||||||
|
"systemExcludeSearchPatterns": [
|
||||||
|
"**/bin/**/*",
|
||||||
|
"**/obj/**/*",
|
||||||
|
"**/node_modules/**/*"
|
||||||
|
],
|
||||||
|
"userExcludeSearchPatterns": []
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace isn
|
||||||
|
{
|
||||||
|
public class APIKO
|
||||||
|
{
|
||||||
|
public string Context { get; set; }
|
||||||
|
public Dictionary<string, string[]> Errors { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using isn.abst;
|
||||||
|
|
||||||
|
namespace isnd.Entities
|
||||||
|
{
|
||||||
|
public static class ApiConfig
|
||||||
|
{
|
||||||
|
public const string Index = "/index.json";
|
||||||
|
public const string Catalog = "/catalog";
|
||||||
|
public const string Package = "/package";
|
||||||
|
public const string Search = "/search";
|
||||||
|
public const string AutoComplete = "/autocomplete";
|
||||||
|
public const string Registration = "/registration";
|
||||||
|
|
||||||
|
public const string Nuspec = "/nuspec";
|
||||||
|
public const string Content = "/content";
|
||||||
|
public const string Nuget = "/nuget";
|
||||||
|
|
||||||
|
[Obsolete("use the V3 search")]
|
||||||
|
|
||||||
|
public const string V2Find = "/v2/FindPackagesById()"; // /FindPackagesById()??$filter=IsLatestVersion&$orderby=Version desc&$top=1&id='isn.abst'
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
using isnd.Data.Catalog;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace isn.Abstract
|
||||||
|
{
|
||||||
|
public class ApiIndexViewModel : Permalink
|
||||||
|
{
|
||||||
|
public ApiIndexViewModel(string id) : base(id, "ApiIndex")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty("version")]
|
||||||
|
public string Version { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("resources")]
|
||||||
|
public Resource[] Resources { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
namespace isn.abst
|
||||||
|
{
|
||||||
|
public static class Constants
|
||||||
|
{
|
||||||
|
public const string PacketFileExtension = "nupkg";
|
||||||
|
public const string SpecFileExtension = "nuspec";
|
||||||
|
public const string ApiVersionPrefix = "/v3";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace isnd.Data.Catalog
|
||||||
|
{
|
||||||
|
public abstract class Permalink
|
||||||
|
{
|
||||||
|
public Permalink(string id)
|
||||||
|
{
|
||||||
|
Type = GetType().Name;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Permalink(string id, string type)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty("@type")]
|
||||||
|
public virtual string Type { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty("@id")]
|
||||||
|
public string Id { get => id; }
|
||||||
|
protected string id;
|
||||||
|
|
||||||
|
public string GetId() { return id; }
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj!=null)
|
||||||
|
{
|
||||||
|
if (GetType().IsAssignableFrom(obj.GetType()))
|
||||||
|
{
|
||||||
|
var rpobj = (Permalink) obj;
|
||||||
|
return this.id == rpobj.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return base.Equals(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return id.GetHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
using isnd.Data.Catalog;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace isn.Abstract
|
||||||
|
{
|
||||||
|
public class Resource : Permalink
|
||||||
|
{
|
||||||
|
public Resource(string id, string typename) : base(id)
|
||||||
|
{
|
||||||
|
Type = typename;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty("comment")]
|
||||||
|
public string Comment {get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace isnd.Attributes
|
||||||
|
{
|
||||||
|
public class SafeNameAttribute : ValidationAttribute
|
||||||
|
{
|
||||||
|
public override bool IsValid(object value)
|
||||||
|
{
|
||||||
|
if (!(value is string))
|
||||||
|
return false;
|
||||||
|
string str = value as string;
|
||||||
|
if (str.Length>126) return false;
|
||||||
|
if (str.Any(c => !char.IsLetterOrDigit(c)
|
||||||
|
&& !"-_.".Contains(c))) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
namespace isn
|
||||||
|
{
|
||||||
|
internal static class Constants
|
||||||
|
{
|
||||||
|
internal const string ClientVersion = "isn v1.0";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
namespace isn
|
||||||
|
{
|
||||||
|
public class IsndErrorMessage
|
||||||
|
{
|
||||||
|
public int ecode { get; set; }
|
||||||
|
public string msg { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace isn
|
||||||
|
{
|
||||||
|
public class SourceSettings
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Protected API Key
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public string ProtectedApiKey { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Key alias
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public string Url { get; set; }
|
||||||
|
|
||||||
|
public SourceSettings()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetClearApiKey(RSA rsa)
|
||||||
|
{
|
||||||
|
var decrypted = rsa.Decrypt(System.Convert.FromBase64String(ProtectedApiKey), RSAEncryptionPadding.Pkcs1);
|
||||||
|
return Encoding.Default.GetString(decrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetApiKey(RSA rsa, string key)
|
||||||
|
{
|
||||||
|
var ciphered =rsa.Encrypt(Encoding.Default.GetBytes(key), RSAEncryptionPadding.Pkcs1);
|
||||||
|
ProtectedApiKey = System.Convert.ToBase64String(ciphered);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Settings
|
||||||
|
{
|
||||||
|
private Settings()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Settings Create()
|
||||||
|
{
|
||||||
|
var rsaParams = CreateCipheringParameters();
|
||||||
|
return new Settings {
|
||||||
|
RSAParameters = rsaParams,
|
||||||
|
Sources = new Dictionary<string, SourceSettings>()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public RSAParameters RSAParameters { get; set; }
|
||||||
|
public Dictionary<string, SourceSettings> Sources { get; set; }
|
||||||
|
|
||||||
|
private string defSourceKey;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default source by its alias
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public string DefaultSourceKey
|
||||||
|
{
|
||||||
|
get => defSourceKey;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
defSourceKey = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[JsonIgnore, NotMapped]
|
||||||
|
public string CurrentSourceKey {get; set;}
|
||||||
|
|
||||||
|
private static RSAParameters CreateCipheringParameters()
|
||||||
|
{
|
||||||
|
var provider = new RSACryptoServiceProvider(2048);
|
||||||
|
return provider.ExportParameters(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonIgnore, NotMapped]
|
||||||
|
public SourceSettings CurrentSource
|
||||||
|
{
|
||||||
|
get => this.Sources[CurrentSourceKey];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using isn.Abstract;
|
||||||
|
|
||||||
|
namespace isn
|
||||||
|
{
|
||||||
|
public static class SourceHelpers
|
||||||
|
{
|
||||||
|
public static ApiIndexViewModel GetServerResources(string url)
|
||||||
|
{
|
||||||
|
HttpClient client = new HttpClient();
|
||||||
|
ApiIndexViewModel result = null;
|
||||||
|
// var json = await client.GetStringAsync(new System.Uri(url));
|
||||||
|
|
||||||
|
Task.Run(async ()=> {
|
||||||
|
try {
|
||||||
|
var response = await client.GetStringAsync(url);
|
||||||
|
result = JsonConvert.DeserializeObject<ApiIndexViewModel>(response);
|
||||||
|
|
||||||
|
} catch (HttpRequestException ex)
|
||||||
|
{
|
||||||
|
if (ex.StatusCode==HttpStatusCode.NotFound)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("Not found ... server's down ?");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"{ex.StatusCode} : {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).Wait();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace isn
|
||||||
|
{
|
||||||
|
public static class UploadFilesToServerUsingHttpClient
|
||||||
|
{
|
||||||
|
public static PushReport UploadFilesToServer(this HttpClient client, Uri uri, FileInfo fi,
|
||||||
|
string apikey)
|
||||||
|
{
|
||||||
|
return UploadFilesToServerAsync(client, uri, fi, apikey).Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<PushReport> UploadFilesToServerAsync(this HttpClient client, Uri uri, FileInfo fi,
|
||||||
|
string apikey)
|
||||||
|
{
|
||||||
|
|
||||||
|
client.DefaultRequestHeaders.Add("X-NuGet-Client-Version", Constants.ClientVersion);
|
||||||
|
client.DefaultRequestHeaders.Add("X-NuGet-ApiKey", apikey);
|
||||||
|
|
||||||
|
using (var multipartFormDataContent = new MultipartFormDataContent())
|
||||||
|
{
|
||||||
|
multipartFormDataContent.Add(new ByteArrayContent(File.ReadAllBytes(fi.FullName)),
|
||||||
|
'"' + "File" + '"',
|
||||||
|
'"' + fi.Name + '"');
|
||||||
|
|
||||||
|
var result = await client.PutAsync(uri, multipartFormDataContent);
|
||||||
|
if (result.IsSuccessStatusCode) return
|
||||||
|
new PushReport() {
|
||||||
|
KO = JsonConvert.DeserializeObject<APIKO>(await result.Content.ReadAsStringAsync())
|
||||||
|
};
|
||||||
|
else
|
||||||
|
return new PushReport() {
|
||||||
|
OK = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace isn
|
||||||
|
{
|
||||||
|
public class PushCommand
|
||||||
|
{
|
||||||
|
Settings settings;
|
||||||
|
|
||||||
|
public PushCommand(Settings settings)
|
||||||
|
{
|
||||||
|
this.settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PushReport Run(string pkg, string source, string apiKey)
|
||||||
|
{
|
||||||
|
|
||||||
|
var resources = SourceHelpers.GetServerResources(source);
|
||||||
|
if (resources == null) return null;
|
||||||
|
if (resources.Resources == null)
|
||||||
|
throw new InvalidOperationException("source gave no resource");
|
||||||
|
if (!resources.Resources.Any(res => res.Type == "PackagePublish/2.0.0"))
|
||||||
|
throw new InvalidOperationException("Source won't serve the expected push command");
|
||||||
|
var pubRes = resources.Resources.First(res => res.Type == "PackagePublish/2.0.0");
|
||||||
|
FileInfo fi = new FileInfo(pkg);
|
||||||
|
if (!fi.Exists)
|
||||||
|
{
|
||||||
|
var report = new PushReport
|
||||||
|
{
|
||||||
|
PkgName = fi.Name,
|
||||||
|
Message = "The package does not exist : " + fi.FullName
|
||||||
|
};
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
using (var client = new HttpClient(
|
||||||
|
new HttpClientHandler
|
||||||
|
{
|
||||||
|
AllowAutoRedirect = false
|
||||||
|
}
|
||||||
|
))
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return client.UploadFilesToServer(new Uri(pubRes.Id), fi, settings.Sources[source].GetClearApiKey(Program.rsa));
|
||||||
|
}
|
||||||
|
catch (HttpRequestException httpEx)
|
||||||
|
{
|
||||||
|
var report = new PushReport
|
||||||
|
{
|
||||||
|
PkgName = fi.Name,
|
||||||
|
Message = "HttpRequest: " + httpEx.Message,
|
||||||
|
StackTrace = httpEx.StackTrace,
|
||||||
|
StatusCode = httpEx.HResult.ToString()
|
||||||
|
};
|
||||||
|
Console.Error.WriteLine(httpEx.Message);
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var report = new PushReport
|
||||||
|
{
|
||||||
|
PkgName = fi.Name,
|
||||||
|
Message = ex.Message,
|
||||||
|
StackTrace = ex.StackTrace
|
||||||
|
};
|
||||||
|
Console.Error.WriteLine(ex.Message);
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
|
||||||
|
namespace isn
|
||||||
|
{
|
||||||
|
|
||||||
|
partial class Program
|
||||||
|
{
|
||||||
|
public static List<PushReport> PushPkg(IEnumerable<string> pkgs)
|
||||||
|
{
|
||||||
|
List<PushReport> pushReports = new List<PushReport>();
|
||||||
|
var cmd = new PushCommand(Settings);
|
||||||
|
|
||||||
|
if (Settings.CurrentSource == null) throw new InvalidOperationException("source is null");
|
||||||
|
var source = Settings.CurrentSource;
|
||||||
|
foreach (string pkg in pkgs)
|
||||||
|
{
|
||||||
|
var report = cmd.Run(pkg, source.Url, source.GetClearApiKey(rsa));
|
||||||
|
pushReports.Add(report);
|
||||||
|
}
|
||||||
|
return pushReports;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object Add(IEnumerable<string> str)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
|
||||||
|
namespace isn
|
||||||
|
{
|
||||||
|
|
||||||
|
partial class Program
|
||||||
|
{
|
||||||
|
|
||||||
|
private static void ShowConfig()
|
||||||
|
{
|
||||||
|
Console.WriteLine(JsonConvert.SerializeObject(Settings, Formatting.Indented));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace isn
|
||||||
|
{
|
||||||
|
|
||||||
|
partial class Program
|
||||||
|
{
|
||||||
|
private static void SourceAdd(IEnumerable<string> str)
|
||||||
|
{
|
||||||
|
foreach (string arg in str)
|
||||||
|
{
|
||||||
|
if (Settings.Sources.ContainsKey(arg))
|
||||||
|
{
|
||||||
|
SourceSettings setting = Settings.Sources[arg];
|
||||||
|
throw new InvalidOperationException
|
||||||
|
(setting.Url);
|
||||||
|
}
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace isn
|
||||||
|
{
|
||||||
|
partial class Program
|
||||||
|
{
|
||||||
|
private static void SourceList(IEnumerable<string> sargs)
|
||||||
|
{
|
||||||
|
IEnumerable<string> spec = sargs.Count()>0 ? sargs : Settings.Sources.Keys;
|
||||||
|
foreach (string arg in spec)
|
||||||
|
{
|
||||||
|
SourceSettings setting = Settings.Sources[arg];
|
||||||
|
Console.WriteLine(JsonConvert.SerializeObject(setting));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace isn
|
||||||
|
{
|
||||||
|
|
||||||
|
partial class Program
|
||||||
|
{
|
||||||
|
private static void SetDefaultSource(string arg)
|
||||||
|
{
|
||||||
|
SourceSettings settings =
|
||||||
|
Settings.Sources.ContainsKey(arg) ?
|
||||||
|
Settings.Sources[arg] :
|
||||||
|
Settings.Sources.Values.FirstOrDefault((s)=> s.Url == arg) ;
|
||||||
|
if (settings==null) throw new InvalidOperationException(arg);
|
||||||
|
Settings.DefaultSourceKey = arg;
|
||||||
|
SaveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
|
||||||
|
namespace isn
|
||||||
|
{
|
||||||
|
|
||||||
|
partial class Program
|
||||||
|
{
|
||||||
|
private static void StoreApiKey(IEnumerable<string> storeArgs)
|
||||||
|
{
|
||||||
|
var args = storeoptions.Parse(storeArgs);
|
||||||
|
if (args.Count != 1)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("StoreApiKey command takes only one argument, the key.");
|
||||||
|
shouldShowPushHelp=true;
|
||||||
|
}
|
||||||
|
if (shouldShowPushHelp)
|
||||||
|
{
|
||||||
|
// output the options
|
||||||
|
Console.Error.WriteLine("StoreApiKey Options:");
|
||||||
|
storeoptions.WriteOptionDescriptions(Console.Out);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Settings.Sources[Settings.CurrentSourceKey].SetApiKey(Program.rsa, args[0]);
|
||||||
|
SaveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SaveConfig()
|
||||||
|
{
|
||||||
|
FileInfo cfgSettingIf = new FileInfo(_configFileName);
|
||||||
|
if (!cfgSettingIf.Directory.Exists) cfgSettingIf.Directory.Create();
|
||||||
|
File.WriteAllText(
|
||||||
|
cfgSettingIf.FullName,
|
||||||
|
JsonConvert.SerializeObject(
|
||||||
|
Settings,
|
||||||
|
Formatting.Indented
|
||||||
|
));
|
||||||
|
Console.WriteLine("config saved .");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
using System.Threading.Tasks.Dataflow;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace isn
|
||||||
|
{
|
||||||
|
public class PushReport
|
||||||
|
{
|
||||||
|
public PushReport()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public string PkgName { get; set; }
|
||||||
|
public bool Executed { get; set; }
|
||||||
|
public bool OK { get; set; }
|
||||||
|
public bool AlreadyPresent { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
public string StatusCode { get; set; }
|
||||||
|
public string StackTrace { get; set; }
|
||||||
|
public APIKO KO { get; set; }
|
||||||
|
|
||||||
|
public string ToDoc()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder($"= push {PkgName}\n\n");
|
||||||
|
if (Executed) sb.AppendLine("* Executed");
|
||||||
|
if (OK) sb.AppendLine("* OK");
|
||||||
|
if (!string.IsNullOrWhiteSpace(Message))
|
||||||
|
sb.AppendLine("* Message :" + Message);
|
||||||
|
if (!string.IsNullOrWhiteSpace(StatusCode))
|
||||||
|
sb.AppendLine($"* Status Code : ");
|
||||||
|
if (!string.IsNullOrWhiteSpace(StackTrace))
|
||||||
|
sb.AppendLine($"* StackTrace : " + StackTrace);
|
||||||
|
if (KO!=null)
|
||||||
|
sb.AppendLine($"* KO : " + KO.Context);
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
|
namespace isnd.Authorization
|
||||||
|
{
|
||||||
|
internal class ValidApiKeyRequirement : IAuthorizationRequirement
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
|
namespace isnd.Authorization
|
||||||
|
{
|
||||||
|
internal class ValidApiKeyRequirementHandler : AuthorizationHandler<ValidApiKeyRequirement>
|
||||||
|
{
|
||||||
|
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ValidApiKeyRequirement requirement)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
namespace isnd
|
||||||
|
{
|
||||||
|
public static class IsndConstants
|
||||||
|
{
|
||||||
|
public const string AdministratorRoleName = "Admin";
|
||||||
|
public const string RequireAdminPolicyName = "RequireAdministratorRole";
|
||||||
|
public const string RequireValidApiKey = "RequireValideApiKey";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,258 @@
|
|||||||
|
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using isnd.Data;
|
||||||
|
using isnd.Data.Roles;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace isnd.Controllers
|
||||||
|
{
|
||||||
|
[AllowAnonymous]
|
||||||
|
public class AccountController : Controller
|
||||||
|
{
|
||||||
|
private readonly IAuthenticationSchemeProvider _schemeProvider;
|
||||||
|
|
||||||
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
|
private readonly AdminStartupList _startupAdminList;
|
||||||
|
|
||||||
|
public AccountController(
|
||||||
|
IAuthenticationSchemeProvider schemeProvider,
|
||||||
|
SignInManager<ApplicationUser> signInManager,
|
||||||
|
UserManager<ApplicationUser> userManager,
|
||||||
|
IOptions<AdminStartupList> startupAdminListConfig )
|
||||||
|
{
|
||||||
|
_schemeProvider = schemeProvider;
|
||||||
|
_signInManager = signInManager;
|
||||||
|
_userManager = userManager;
|
||||||
|
_startupAdminList = startupAdminListConfig.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Entry point into the login workflow
|
||||||
|
/// </summary>
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> Login(string returnUrl)
|
||||||
|
{
|
||||||
|
// build a model so we know what to show on the login page
|
||||||
|
var vm = await BuildLoginViewModelAsync(returnUrl);
|
||||||
|
|
||||||
|
if (vm.IsExternalLoginOnly)
|
||||||
|
{
|
||||||
|
// we only have one option for logging in and it's an external provider
|
||||||
|
return RedirectToAction("Challenge", "External", new { scheme = vm.ExternalLoginScheme, returnUrl });
|
||||||
|
}
|
||||||
|
|
||||||
|
return View(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handle postback from username/password login
|
||||||
|
/// </summary>
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> Login(LoginInputModel model, string button)
|
||||||
|
{
|
||||||
|
|
||||||
|
// the user clicked the "cancel" button
|
||||||
|
if (button != "login")
|
||||||
|
{
|
||||||
|
|
||||||
|
// since we don't have a valid context, then we just go back to the home page
|
||||||
|
return Redirect("~/");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ModelState.IsValid)
|
||||||
|
{
|
||||||
|
// validate username/password
|
||||||
|
var user = await _userManager.FindByNameAsync(model.Username);
|
||||||
|
var signResult = await _signInManager.CheckPasswordSignInAsync(user, model.Password, true);
|
||||||
|
|
||||||
|
if (signResult.Succeeded)
|
||||||
|
{
|
||||||
|
|
||||||
|
// only set explicit expiration here if user chooses "remember me".
|
||||||
|
// otherwise we rely upon expiration configured in cookie middleware.
|
||||||
|
AuthenticationProperties props = null;
|
||||||
|
if (AccountOptions.AllowRememberLogin && model.RememberLogin)
|
||||||
|
{
|
||||||
|
props = new AuthenticationProperties
|
||||||
|
{
|
||||||
|
IsPersistent = true,
|
||||||
|
ExpiresUtc = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
await _signInManager.SignInAsync(user, model.RememberLogin && AccountOptions.AllowRememberLogin);
|
||||||
|
if (Url.IsLocalUrl(model.ReturnUrl))
|
||||||
|
{
|
||||||
|
return Redirect(model.ReturnUrl);
|
||||||
|
}
|
||||||
|
else if (string.IsNullOrEmpty(model.ReturnUrl))
|
||||||
|
{
|
||||||
|
return Redirect("~/");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// user might have clicked on a malicious link - should be logged
|
||||||
|
throw new Exception("invalid return URL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelState.AddModelError(string.Empty, AccountOptions.InvalidCredentialsErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// something went wrong, show form with error
|
||||||
|
var vm = await BuildLoginViewModelAsync(model);
|
||||||
|
return View(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Show logout page
|
||||||
|
/// </summary>
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> Logout(string logoutId)
|
||||||
|
{
|
||||||
|
// build a model so the logout page knows what to display
|
||||||
|
var vm = BuildLogoutViewModel(logoutId);
|
||||||
|
|
||||||
|
if (vm.ShowLogoutPrompt == false)
|
||||||
|
{
|
||||||
|
// if the request for logout was properly authenticated from IdentityServer, then
|
||||||
|
// we don't need to show the prompt and can just log the user out directly.
|
||||||
|
return await Logout(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
return View(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handle logout page postback
|
||||||
|
/// </summary>
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> Logout(LogoutInputModel model)
|
||||||
|
{
|
||||||
|
// build a model so the logged out page knows what to display
|
||||||
|
var vm = BuildLoggedOutViewModel(model.LogoutId);
|
||||||
|
|
||||||
|
if (User?.Identity.IsAuthenticated == true)
|
||||||
|
{
|
||||||
|
// delete local authentication cookie
|
||||||
|
await HttpContext.SignOutAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we need to trigger sign-out at an upstream identity provider
|
||||||
|
if (vm.TriggerExternalSignout)
|
||||||
|
{
|
||||||
|
// build a return URL so the upstream provider will redirect back
|
||||||
|
// to us after the user has logged out. this allows us to then
|
||||||
|
// complete our single sign-out processing.
|
||||||
|
string url = Url.Action("Logout", new { logoutId = vm.LogoutId });
|
||||||
|
|
||||||
|
// this triggers a redirect to the external provider for sign-out
|
||||||
|
return SignOut(new AuthenticationProperties { RedirectUri = url }, vm.ExternalAuthenticationScheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
return View("LoggedOut", vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult AccessDenied()
|
||||||
|
{
|
||||||
|
return new BadRequestObjectResult(403);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************/
|
||||||
|
/* helper APIs for the AccountController */
|
||||||
|
/*****************************************/
|
||||||
|
private async Task<LoginViewModel> BuildLoginViewModelAsync(string returnUrl)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
var schemes = await _schemeProvider.GetAllSchemesAsync();
|
||||||
|
|
||||||
|
var providers = schemes
|
||||||
|
.Where(x => x.DisplayName != null)
|
||||||
|
.Select(x => new ExternalProvider
|
||||||
|
{
|
||||||
|
DisplayName = x.DisplayName ?? x.Name,
|
||||||
|
AuthenticationScheme = x.Name
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
var allowLocal = true;
|
||||||
|
|
||||||
|
|
||||||
|
return new LoginViewModel
|
||||||
|
{
|
||||||
|
AllowRememberLogin = AccountOptions.AllowRememberLogin,
|
||||||
|
EnableLocalLogin = allowLocal && AccountOptions.AllowLocalLogin,
|
||||||
|
ReturnUrl = returnUrl,
|
||||||
|
ExternalProviders = providers.ToArray()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<LoginViewModel> BuildLoginViewModelAsync(LoginInputModel model)
|
||||||
|
{
|
||||||
|
var vm = await BuildLoginViewModelAsync(model.ReturnUrl);
|
||||||
|
vm.Username = model.Username;
|
||||||
|
vm.RememberLogin = model.RememberLogin;
|
||||||
|
return vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LogoutViewModel BuildLogoutViewModel(string logoutId)
|
||||||
|
{
|
||||||
|
var vm = new LogoutViewModel { LogoutId = logoutId, ShowLogoutPrompt = AccountOptions.ShowLogoutPrompt };
|
||||||
|
|
||||||
|
if (User?.Identity.IsAuthenticated != true)
|
||||||
|
{
|
||||||
|
// if the user is not authenticated, then just show logged out page
|
||||||
|
vm.ShowLogoutPrompt = false;
|
||||||
|
return vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
// show the logout prompt. this prevents attacks where the user
|
||||||
|
// is automatically signed out by another malicious web page.
|
||||||
|
return vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoggedOutViewModel BuildLoggedOutViewModel(string logoutId)
|
||||||
|
{
|
||||||
|
var vm = new LoggedOutViewModel
|
||||||
|
{
|
||||||
|
AutomaticRedirectAfterSignOut = AccountOptions.AutomaticRedirectAfterSignOut,
|
||||||
|
LogoutId = logoutId
|
||||||
|
};
|
||||||
|
return vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize]
|
||||||
|
public async Task<IActionResult> GetAdminrole()
|
||||||
|
{
|
||||||
|
string username = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||||
|
if (_startupAdminList.Users.Contains(username))
|
||||||
|
{
|
||||||
|
var user = await _userManager.FindByNameAsync(username);
|
||||||
|
var roles = await _userManager.GetRolesAsync(user);
|
||||||
|
if (!roles.Contains(IsndConstants.AdministratorRoleName))
|
||||||
|
{
|
||||||
|
await _userManager.AddToRoleAsync(user, IsndConstants.AdministratorRoleName);
|
||||||
|
|
||||||
|
}
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,148 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.DataProtection;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using isnd.Data;
|
||||||
|
using isnd.Entities;
|
||||||
|
using isnd.Data.ApiKeys;
|
||||||
|
using isnd.Interfaces;
|
||||||
|
|
||||||
|
|
||||||
|
namespace isnd.Controllers
|
||||||
|
{
|
||||||
|
[Authorize]
|
||||||
|
public class ApiKeysController : Controller
|
||||||
|
{
|
||||||
|
private readonly ApplicationDbContext dbContext;
|
||||||
|
private readonly IsndSettings isndSettings;
|
||||||
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
|
private readonly IApiKeyProvider apiKeyProvider;
|
||||||
|
private readonly IDataProtector protector;
|
||||||
|
public ApiKeysController(ApplicationDbContext dbContext,
|
||||||
|
IOptions<IsndSettings> isndSettingsOptions,
|
||||||
|
IDataProtectionProvider provider,
|
||||||
|
UserManager<ApplicationUser> userManager,
|
||||||
|
IApiKeyProvider apiKeyProvider
|
||||||
|
)
|
||||||
|
{
|
||||||
|
this.dbContext = dbContext;
|
||||||
|
this.isndSettings = isndSettingsOptions.Value;
|
||||||
|
protector = provider.CreateProtector(isndSettings.ProtectionTitle);
|
||||||
|
_userManager = userManager;
|
||||||
|
this.apiKeyProvider = apiKeyProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<ActionResult> Index()
|
||||||
|
{
|
||||||
|
List<ApiKey> index = await GetUserKeys().ToListAsync();
|
||||||
|
IndexModel model = new IndexModel { ApiKey = index };
|
||||||
|
ViewData["Title"] = "Index";
|
||||||
|
return View("Index", model);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<ActionResult> Create()
|
||||||
|
{
|
||||||
|
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||||
|
var user = await _userManager.FindByIdAsync(userId);
|
||||||
|
ViewBag.UserId = new SelectList(new List<ApplicationUser> { user });
|
||||||
|
return View(new CreateModel{ });
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<ActionResult> Create(CreateModel model)
|
||||||
|
{
|
||||||
|
string userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||||
|
IQueryable<ApiKey> userKeys = apiKeyProvider.GetUserKeys(User.Identity.Name);
|
||||||
|
if (userKeys.Count() >= isndSettings.MaxUserKeyCount)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(null, "Maximum key count reached");
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
model.UserId = userId;
|
||||||
|
|
||||||
|
ApiKey newKey = await apiKeyProvider.CreateApiKeyAsync(model);
|
||||||
|
|
||||||
|
return View("Details", new DetailModel { Name = newKey.Name,
|
||||||
|
ProtectedValue = protector.Protect(newKey.Id),
|
||||||
|
ApiKey = newKey });
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<ActionResult> Delete(string id)
|
||||||
|
{
|
||||||
|
string userid = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||||
|
ApiKey key = await dbContext.ApiKeys.FirstOrDefaultAsync(k => k.Id == id && k.UserId == userid);
|
||||||
|
return View(new DeleteModel { ApiKey = key });
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<ActionResult> Delete(DeleteModel model)
|
||||||
|
{
|
||||||
|
string userid = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||||
|
ApiKey key = dbContext.ApiKeys.FirstOrDefault(k => k.Id == model.ApiKey.Id && k.UserId == userid);
|
||||||
|
if (key == null)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(null, "Key not found");
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
_ = dbContext.ApiKeys.Remove(key);
|
||||||
|
_ = await dbContext.SaveChangesAsync();
|
||||||
|
return View("Index", new IndexModel { ApiKey = GetUserKeys().ToList() } );
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ActionResult> Details(string id)
|
||||||
|
{
|
||||||
|
string userid = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||||
|
ApiKey key = await dbContext.ApiKeys.FirstOrDefaultAsync(k => k.Id == id && k.UserId == userid);
|
||||||
|
if (key == null)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError("id", "Key not found");
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
return View("Details", new DetailModel { ApiKey = key, Name = key.Name, ProtectedValue = protector.Protect(key.Id)});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ActionResult> Edit(string id)
|
||||||
|
{
|
||||||
|
|
||||||
|
EditModel edit = new EditModel();
|
||||||
|
string userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||||
|
|
||||||
|
var user = await _userManager.FindByIdAsync(userId);
|
||||||
|
|
||||||
|
edit.ApiKey = await GetUserKeys().SingleOrDefaultAsync(k =>
|
||||||
|
k.UserId == userId && k.Id == id);
|
||||||
|
ViewBag.UserId = new SelectList(new List<ApplicationUser> { user });
|
||||||
|
|
||||||
|
return View(edit);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<ActionResult> Edit(EditModel model)
|
||||||
|
{
|
||||||
|
string userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||||
|
|
||||||
|
var apiKey = await dbContext.ApiKeys.SingleOrDefaultAsync(k => k.UserId == userId && k.Id == model.ApiKey.Id);
|
||||||
|
apiKey.Name = model.ApiKey.Name;
|
||||||
|
apiKey.ValidityPeriodInDays = model.ApiKey.ValidityPeriodInDays;
|
||||||
|
await dbContext.SaveChangesAsync();
|
||||||
|
return View("Details", new DetailModel { ApiKey = apiKey });
|
||||||
|
}
|
||||||
|
|
||||||
|
public IQueryable<ApiKey> GetUserKeys()
|
||||||
|
{
|
||||||
|
return dbContext.ApiKeys.Include(k => k.User).Where(k => k.User.UserName == User.Identity.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using isnd.Data;
|
||||||
|
|
||||||
|
namespace isnd.Controllers
|
||||||
|
{
|
||||||
|
|
||||||
|
// TODO Web hook CI
|
||||||
|
public class NewUpdateController : Controller
|
||||||
|
{
|
||||||
|
[Authorize(Policy = IsndConstants.RequireAdminPolicyName)]
|
||||||
|
public IActionResult NewRelease(NewReleaseInfo release)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException("web hook");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using isnd.Data;
|
||||||
|
using isnd.ViewModels;
|
||||||
|
using isnd.Helpers;
|
||||||
|
using isnd.Interfaces;
|
||||||
|
|
||||||
|
namespace isnd
|
||||||
|
{
|
||||||
|
[AllowAnonymous]
|
||||||
|
public class PackageVersionController : Controller
|
||||||
|
{
|
||||||
|
private readonly ApplicationDbContext _context;
|
||||||
|
private readonly IPackageManager _pm;
|
||||||
|
|
||||||
|
public PackageVersionController(ApplicationDbContext context,
|
||||||
|
IPackageManager pm)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_pm = pm;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET: PackageVersion
|
||||||
|
public async Task<IActionResult> Index(PackageVersionIndexViewModel model)
|
||||||
|
{
|
||||||
|
var applicationDbContext = _context.PackageVersions.Include(p => p.Package)
|
||||||
|
.Include(p => p.Package.Owner)
|
||||||
|
.Include(p => p.Package.Versions)
|
||||||
|
.Where(
|
||||||
|
p => (model.Prerelease || !p.IsPrerelease)
|
||||||
|
&& ((model.PackageId == null) || p.PackageId.StartsWith(model.PackageId)));
|
||||||
|
model.Versions = await applicationDbContext.ToArrayAsync();
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize]
|
||||||
|
public async Task<IActionResult> Mines(PackageVersionIndexViewModel model)
|
||||||
|
{
|
||||||
|
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||||
|
var applicationDbContext = _context.PackageVersions
|
||||||
|
.Include(p => p.Package).Where(
|
||||||
|
p => (string.IsNullOrEmpty(model.PackageId) || p.PackageId.StartsWith(model.PackageId))
|
||||||
|
&& p.Package.OwnerId == userId);
|
||||||
|
|
||||||
|
model.Versions = await applicationDbContext.ToArrayAsync();
|
||||||
|
|
||||||
|
return View("Index", model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using isnd.Services;
|
||||||
|
using isn.Abstract;
|
||||||
|
using isn.abst;
|
||||||
|
using isnd.Interfaces;
|
||||||
|
using System.Linq;
|
||||||
|
using isnd.Entities;
|
||||||
|
|
||||||
|
namespace isnd.Controllers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Api Controller
|
||||||
|
/// </summary>
|
||||||
|
public class ApiController : Controller
|
||||||
|
{
|
||||||
|
private readonly IPackageManager packageManager;
|
||||||
|
private readonly Resource[] resources;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Api Controller Constructor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pm"></param>
|
||||||
|
public ApiController(IPackageManager pm)
|
||||||
|
{
|
||||||
|
packageManager = pm;
|
||||||
|
resources = packageManager.GetResources().ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// API index
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Index)]
|
||||||
|
public IActionResult ApiIndex()
|
||||||
|
{
|
||||||
|
return Ok(new ApiIndexViewModel(packageManager.CatalogBaseUrl){ Version = PackageManager.BASE_API_LEVEL, Resources = resources });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
using isnd.Services;
|
||||||
|
using isnd.Entities;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using isn.abst;
|
||||||
|
|
||||||
|
namespace isnd.Controllers
|
||||||
|
{
|
||||||
|
public partial class PackagesController
|
||||||
|
{
|
||||||
|
|
||||||
|
// GET /autocomplete?id=isn.protocol&prerelease=true
|
||||||
|
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.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");
|
||||||
|
}
|
||||||
|
if (semVerLevel != PackageManager.BASE_API_LEVEL)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError("semVerLevel", PackageManager.BASE_API_LEVEL + " expected");
|
||||||
|
}
|
||||||
|
if (ModelState.ErrorCount > 0) return BadRequest(ModelState);
|
||||||
|
|
||||||
|
return Ok(packageManager.AutoComplete(id,skip,take,prerelease,packageType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using isnd.Entities;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using isn.abst;
|
||||||
|
|
||||||
|
namespace isnd.Controllers
|
||||||
|
{
|
||||||
|
public partial class PackagesController
|
||||||
|
{
|
||||||
|
|
||||||
|
// https://docs.microsoft.com/en-us/nuget/api/catalog-resource#versioning
|
||||||
|
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Catalog)]
|
||||||
|
public async Task<IActionResult> CatalogIndex()
|
||||||
|
{
|
||||||
|
return Ok(await packageManager.GetCatalogIndexAsync());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Content + "/{id}/{version}.json")]
|
||||||
|
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Registration + "/{id}/{version}.json")]
|
||||||
|
public async Task<IActionResult> CatalogRegistration(string id, string version)
|
||||||
|
{
|
||||||
|
if ("index" == version)
|
||||||
|
{
|
||||||
|
var query = new Data.Catalog.PackageRegistrationQuery
|
||||||
|
{
|
||||||
|
Query = id,
|
||||||
|
Prerelease = true
|
||||||
|
};
|
||||||
|
var index = await packageManager.GetPackageRegistrationIndexAsync(query);
|
||||||
|
if (index == null) return NotFound();
|
||||||
|
|
||||||
|
return Ok(index);
|
||||||
|
}
|
||||||
|
// return a Package
|
||||||
|
var leaf = await packageManager.GetCatalogEntryAsync(id, version, null);
|
||||||
|
|
||||||
|
if (null == leaf) return NotFound(new { id, version });
|
||||||
|
return Ok(leaf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using isnd.Helpers;
|
||||||
|
using isnd.Entities;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using isnd.Attributes;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using isn.abst;
|
||||||
|
|
||||||
|
namespace isnd.Controllers
|
||||||
|
{
|
||||||
|
public partial class PackagesController
|
||||||
|
{
|
||||||
|
[HttpDelete("~" + Constants.ApiVersionPrefix + ApiConfig.Package + "/{id}/{lower?}/{type?}")]
|
||||||
|
public async Task<IActionResult> ApiDelete(
|
||||||
|
[FromRoute][SafeName][Required] string id,
|
||||||
|
[FromRoute][SafeName][Required] string lower,
|
||||||
|
[FromRoute] string type)
|
||||||
|
{
|
||||||
|
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||||
|
var report = await packageManager.UserAskForPackageDeletionAsync(uid, id, lower, type);
|
||||||
|
return Ok(report);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.IO;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using isnd.Attributes;
|
||||||
|
using isnd.Entities;
|
||||||
|
using isn.abst;
|
||||||
|
|
||||||
|
namespace isnd.Controllers
|
||||||
|
{
|
||||||
|
public partial class PackagesController
|
||||||
|
{
|
||||||
|
// Web get the paquet
|
||||||
|
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Nuget + "/{id}/{lower}/{idf}-{lowerFromName}."
|
||||||
|
+ Constants.PacketFileExtension)]
|
||||||
|
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Content + "/{id}/{lower}/{idf}-{lowerFromName}."
|
||||||
|
+ Constants.PacketFileExtension)]
|
||||||
|
public IActionResult GetPackage(
|
||||||
|
[FromRoute][SafeName][Required] string id,
|
||||||
|
[FromRoute][SafeName][Required] string lower,
|
||||||
|
[FromRoute] string idf, [FromRoute] string lowerFromName)
|
||||||
|
{
|
||||||
|
var pkgPath = Path.Combine(isndSettings.PackagesRootDir,
|
||||||
|
id, lower, $"{id}-{lower}." + Constants.PacketFileExtension
|
||||||
|
);
|
||||||
|
|
||||||
|
FileInfo pkgFileInfo = new FileInfo(pkgPath);
|
||||||
|
|
||||||
|
if (!pkgFileInfo.Exists)
|
||||||
|
{
|
||||||
|
return BadRequest("!pkgFileInfo.Exists");
|
||||||
|
}
|
||||||
|
return File(pkgFileInfo.OpenRead(), "application/zip; charset=binary");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Web get spec
|
||||||
|
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Nuspec + "/{id}/{lower}/{idf}-{lowerFromName}."
|
||||||
|
+ Constants.SpecFileExtension)]
|
||||||
|
public IActionResult GetNuspec(
|
||||||
|
[FromRoute][SafeName][Required] string id,
|
||||||
|
[FromRoute][SafeName][Required] string lower,
|
||||||
|
[FromRoute][SafeName][Required] string idf,
|
||||||
|
[FromRoute][SafeName][Required] string lowerFromName)
|
||||||
|
{
|
||||||
|
var pkgPath = Path.Combine(isndSettings.PackagesRootDir,
|
||||||
|
id, lower, $"{id}." + Constants.SpecFileExtension);
|
||||||
|
|
||||||
|
FileInfo pkgFileInfo = new FileInfo(pkgPath);
|
||||||
|
if (!pkgFileInfo.Exists)
|
||||||
|
{
|
||||||
|
return BadRequest("!pkgFileInfo.Exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
return File(pkgFileInfo.OpenRead(), "text/xml; charset=utf-8");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using NuGet.Versioning;
|
||||||
|
using isnd.Entities;
|
||||||
|
|
||||||
|
namespace isnd.Controllers
|
||||||
|
{
|
||||||
|
public partial class PackagesController
|
||||||
|
{
|
||||||
|
[HttpGet("~" + ApiConfig.V2Find)]
|
||||||
|
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)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.DataProtection;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using isnd.Entities;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using isn.abst;
|
||||||
|
|
||||||
|
namespace isnd.Controllers
|
||||||
|
{
|
||||||
|
|
||||||
|
public partial class PackagesController
|
||||||
|
{
|
||||||
|
// TODO [Authorize(Policy = IsndConstants.RequireValidApiKey)]
|
||||||
|
[HttpPut("~" + Constants.ApiVersionPrefix + ApiConfig.Package)]
|
||||||
|
public async Task<IActionResult> Put()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var clientVersionId = Request.Headers["X-NuGet-Client-Version"];
|
||||||
|
string apiKey = Request.Headers["X-NuGet-ApiKey"][0];
|
||||||
|
ViewData["versionId"] = typeof(PackagesController).Assembly.FullName;
|
||||||
|
var files = new List<string>();
|
||||||
|
ViewData["files"] = files;
|
||||||
|
|
||||||
|
var clearKey = protector.Unprotect(apiKey);
|
||||||
|
var dbApiKey = dbContext.ApiKeys.SingleOrDefault(k => k.Id == clearKey);
|
||||||
|
if (dbApiKey == null)
|
||||||
|
{
|
||||||
|
logger.LogError("403 : no api-key");
|
||||||
|
return Unauthorized();
|
||||||
|
}
|
||||||
|
foreach (IFormFile file in Request.Form.Files)
|
||||||
|
{
|
||||||
|
var version = await packageManager.PutPackageAsync(file.OpenReadStream(), dbApiKey.UserId);
|
||||||
|
logger.LogInformation($"new package : {version.PackageId} {version.NugetLink}");
|
||||||
|
}
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var message = $"PUT exception : {ex.Message} ({ex.GetType().Name})";
|
||||||
|
logger.LogError(message);
|
||||||
|
logger.LogError("Stack Trace : " + ex.StackTrace);
|
||||||
|
return new ObjectResult(new { ViewData, message })
|
||||||
|
{ StatusCode = 500 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using isnd.Entities;
|
||||||
|
using isn.abst;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using isnd.Data.Catalog;
|
||||||
|
|
||||||
|
namespace isnd.Controllers
|
||||||
|
{
|
||||||
|
// TODO /search GET {@id}?q={QUERY}&skip={SKIP}&take={TAKE}&prerelease={PRERELEASE}&semVerLevel={SEMVERLEVEL}&packageType={PACKAGETYPE}
|
||||||
|
|
||||||
|
public partial class PackagesController
|
||||||
|
{
|
||||||
|
// Web get the paquet
|
||||||
|
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Search)]
|
||||||
|
[HttpHead("~" + Constants.ApiVersionPrefix + ApiConfig.Search)]
|
||||||
|
[HttpHead("~" + ApiConfig.V2Find)]
|
||||||
|
public async Task<IActionResult> Search(
|
||||||
|
string q=null,
|
||||||
|
int skip=0,
|
||||||
|
int take=25,
|
||||||
|
bool prerelease=false,
|
||||||
|
string semVerLevel = "2.0.0",
|
||||||
|
string packageType = "Dependency")
|
||||||
|
{
|
||||||
|
PackageRegistrationQuery query = new PackageRegistrationQuery
|
||||||
|
{
|
||||||
|
Prerelease= prerelease,
|
||||||
|
Query = q,
|
||||||
|
Skip = skip,
|
||||||
|
Take = take
|
||||||
|
};
|
||||||
|
var result = await packageManager.SearchPackageAsync(query);
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,106 @@
|
|||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using isn.abst;
|
||||||
|
using isnd.Data;
|
||||||
|
using isnd.Data.Catalog;
|
||||||
|
using isnd.Entities;
|
||||||
|
using isnd.Helpers;
|
||||||
|
using isnd.ViewModels;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Components.Web.Virtualization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace isnd.Controllers
|
||||||
|
{
|
||||||
|
|
||||||
|
public partial class PackagesController
|
||||||
|
{
|
||||||
|
// Web search
|
||||||
|
public async Task<IActionResult> Index(PackageRegistrationQuery model)
|
||||||
|
{
|
||||||
|
var pkgs = await packageManager.SearchPackageAsync(model);
|
||||||
|
var result = new RegistrationPageIndexQueryAndResult
|
||||||
|
{
|
||||||
|
Source = packageManager.CatalogBaseUrl+ApiConfig.Index,
|
||||||
|
Query = model
|
||||||
|
};
|
||||||
|
List<PackageRegistration> registrations = new List<PackageRegistration>();
|
||||||
|
foreach (var pk in pkgs.data.GroupBy(x => x.PackageId))
|
||||||
|
{
|
||||||
|
registrations.Add(new PackageRegistration(apiBase, pk.Key, pkgs.GetResults().Single(p=>p.Id == pk.Key).Versions));
|
||||||
|
}
|
||||||
|
|
||||||
|
return View(new RegistrationPageIndexQueryAndResult
|
||||||
|
{
|
||||||
|
Source = packageManager.CatalogBaseUrl+ApiConfig.Index,
|
||||||
|
Query = model,
|
||||||
|
Result = registrations.ToArray()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> Details(PackageDetailViewModel model)
|
||||||
|
{
|
||||||
|
if (model.pkgid == null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
var packageVersion = dbContext.PackageVersions
|
||||||
|
.Include(p=>p.LatestCommit)
|
||||||
|
.Include(p => p.Package)
|
||||||
|
.Where(m => m.PackageId == model.pkgid)
|
||||||
|
.OrderByDescending(p => p)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (packageVersion.Count() == 0)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
bool results = await packageVersion.AnyAsync();
|
||||||
|
model.latest = await packageVersion.FirstAsync();
|
||||||
|
model.totalHits = packageVersion.Count();
|
||||||
|
model.data = packageVersion.Take(MAX_PKG_VERSION_LIST).ToArray();
|
||||||
|
|
||||||
|
return View("Details", model);
|
||||||
|
}
|
||||||
|
const int MAX_PKG_VERSION_LIST = 50;
|
||||||
|
|
||||||
|
[Authorize, HttpGet]
|
||||||
|
public async Task<IActionResult> Delete(string pkgid, string version, string pkgtype)
|
||||||
|
{
|
||||||
|
if (pkgid == null || version == null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
var packageVersion = await dbContext.PackageVersions.Include(p => p.Package)
|
||||||
|
.FirstOrDefaultAsync(m => m.PackageId == pkgid && m.FullString == version
|
||||||
|
&& (pkgtype!=null && m.Type == pkgtype || m.Type != "Delete" ));
|
||||||
|
if (packageVersion == null) return NotFound();
|
||||||
|
if (!User.IsOwner(packageVersion)) return Unauthorized();
|
||||||
|
var pkg = await packageManager.GetPackageAsync(pkgid, version, pkgtype);
|
||||||
|
return View(pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST: PackageVersion/Delete/5
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken][Authorize]
|
||||||
|
public async Task<IActionResult> DeleteConfirmed(string pkgid, string version,
|
||||||
|
string type)
|
||||||
|
{
|
||||||
|
var packageVersion = await dbContext.PackageVersions
|
||||||
|
.Include(pv => pv.Package)
|
||||||
|
.Where(m => m.PackageId == pkgid
|
||||||
|
&& m.FullString == version && (type==null || m.Type == type))
|
||||||
|
.ToArrayAsync();
|
||||||
|
if (packageVersion.Length==0) return NotFound();
|
||||||
|
if (!User.IsOwner(packageVersion.First())) return Unauthorized();
|
||||||
|
await packageManager.DeletePackageAsync(pkgid, version, type);
|
||||||
|
return RedirectToAction(nameof(Index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.DataProtection;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using isnd.Data;
|
||||||
|
using isnd.Entities;
|
||||||
|
using isnd.Interfaces;
|
||||||
|
using isn.Abstract;
|
||||||
|
using isn.abst;
|
||||||
|
|
||||||
|
namespace isnd.Controllers
|
||||||
|
{
|
||||||
|
[AllowAnonymous]
|
||||||
|
public partial class PackagesController : Controller
|
||||||
|
{
|
||||||
|
const int maxTake = 100;
|
||||||
|
private readonly Resource[] resources;
|
||||||
|
private readonly string apiBase;
|
||||||
|
private readonly ILogger<PackagesController> logger;
|
||||||
|
private readonly IDataProtector protector;
|
||||||
|
|
||||||
|
private readonly IsndSettings isndSettings;
|
||||||
|
readonly ApplicationDbContext dbContext;
|
||||||
|
private readonly IPackageManager packageManager;
|
||||||
|
|
||||||
|
public PackagesController(
|
||||||
|
ILoggerFactory loggerFactory,
|
||||||
|
IDataProtectionProvider provider,
|
||||||
|
IOptions<IsndSettings> isndOptions,
|
||||||
|
ApplicationDbContext dbContext,
|
||||||
|
IPackageManager pm)
|
||||||
|
{
|
||||||
|
logger = loggerFactory.CreateLogger<PackagesController>();
|
||||||
|
isndSettings = isndOptions.Value;
|
||||||
|
protector = provider.CreateProtector(isndSettings.ProtectionTitle);
|
||||||
|
this.dbContext = dbContext;
|
||||||
|
packageManager = pm;
|
||||||
|
resources = packageManager.GetResources().ToArray();
|
||||||
|
this.apiBase = isndSettings.ExternalUrl + Constants.ApiVersionPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
|
||||||
|
|
||||||
|
|
||||||
|
namespace isnd.Data
|
||||||
|
{
|
||||||
|
public class LoggedOutViewModel
|
||||||
|
{
|
||||||
|
public string PostLogoutRedirectUri { get; set; }
|
||||||
|
public string ClientName { get; set; }
|
||||||
|
public string SignOutIframeUrl { get; set; }
|
||||||
|
|
||||||
|
public bool AutomaticRedirectAfterSignOut { get; set; }
|
||||||
|
|
||||||
|
public string LogoutId { get; set; }
|
||||||
|
public bool TriggerExternalSignout => ExternalAuthenticationScheme != null;
|
||||||
|
public string ExternalAuthenticationScheme { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
|
||||||
|
|
||||||
|
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace isnd.Data
|
||||||
|
{
|
||||||
|
public class LoginInputModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string Username { get; set; }
|
||||||
|
[Required]
|
||||||
|
public string Password { get; set; }
|
||||||
|
public bool RememberLogin { get; set; }
|
||||||
|
public string ReturnUrl { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace isnd.Data
|
||||||
|
{
|
||||||
|
public class LoginViewModel : LoginInputModel
|
||||||
|
{
|
||||||
|
public bool AllowRememberLogin { get; set; } = true;
|
||||||
|
public bool EnableLocalLogin { get; set; } = true;
|
||||||
|
|
||||||
|
public IEnumerable<ExternalProvider> ExternalProviders { get; set; } = Enumerable.Empty<ExternalProvider>();
|
||||||
|
public IEnumerable<ExternalProvider> VisibleExternalProviders => ExternalProviders.Where(x => !String.IsNullOrWhiteSpace(x.DisplayName));
|
||||||
|
|
||||||
|
public bool IsExternalLoginOnly => EnableLocalLogin == false && ExternalProviders?.Count() == 1;
|
||||||
|
public string ExternalLoginScheme => IsExternalLoginOnly ? ExternalProviders?.SingleOrDefault()?.AuthenticationScheme : null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
|
||||||
|
|
||||||
|
|
||||||
|
namespace isnd.Data
|
||||||
|
{
|
||||||
|
public class LogoutViewModel : LogoutInputModel
|
||||||
|
{
|
||||||
|
public bool ShowLogoutPrompt { get; set; } = true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace isnd.Data
|
||||||
|
{
|
||||||
|
public class RedirectViewModel
|
||||||
|
{
|
||||||
|
public string RedirectUrl { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace isnd.Data.ApiKeys
|
||||||
|
{
|
||||||
|
public class ApiKey
|
||||||
|
{
|
||||||
|
[Required][Key][DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
[Required][ForeignKey("User")]
|
||||||
|
public string UserId { get; set; }
|
||||||
|
|
||||||
|
public virtual ApplicationUser User { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public int ValidityPeriodInDays{ get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset CreationDate { get; set; }
|
||||||
|
|
||||||
|
public bool IsValid => CreationDate.AddDays(ValidityPeriodInDays) > DateTime.Now;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace isnd.Data.ApiKeys
|
||||||
|
{
|
||||||
|
public class ApiKeyViewModel
|
||||||
|
{
|
||||||
|
[Display(Name = "Key Name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[Display(Name = "Key Value")]
|
||||||
|
public string ProtectedValue { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace isnd.Data.ApiKeys
|
||||||
|
{
|
||||||
|
public class CreateModel
|
||||||
|
{
|
||||||
|
|
||||||
|
[Required][StringLength(255)]
|
||||||
|
[Display(Name = "Key Name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string UserId { get; set; }
|
||||||
|
|
||||||
|
public int ValidityPeriodInDays { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
namespace isnd.Data.ApiKeys
|
||||||
|
{
|
||||||
|
public class DeleteModel
|
||||||
|
{
|
||||||
|
public ApiKey ApiKey { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
namespace isnd.Data.ApiKeys
|
||||||
|
{
|
||||||
|
public class DetailModel : ApiKeyViewModel
|
||||||
|
{
|
||||||
|
public ApiKey ApiKey { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
namespace isnd.Data.ApiKeys
|
||||||
|
{
|
||||||
|
public class EditModel
|
||||||
|
{
|
||||||
|
public EditModel()
|
||||||
|
{
|
||||||
|
if (ApiKey==null) ApiKey = new ApiKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApiKey ApiKey { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace isnd.Data.ApiKeys
|
||||||
|
{
|
||||||
|
public class IndexModel
|
||||||
|
{
|
||||||
|
public List<ApiKey> ApiKey { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
using NuGet.Versioning;
|
||||||
|
|
||||||
|
namespace isnd.Data.Catalog
|
||||||
|
{
|
||||||
|
public class AlternatePackage
|
||||||
|
{
|
||||||
|
public string id { get ; set; }
|
||||||
|
public VersionRange range { get ; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using isnd.Data.Packages;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using NuGet.Versioning;
|
||||||
|
|
||||||
|
namespace isnd.Data.Catalog
|
||||||
|
{
|
||||||
|
public class RegistrationPage : Permalink
|
||||||
|
{
|
||||||
|
private readonly string pkgid;
|
||||||
|
private readonly List<RegistrationLeaf> items;
|
||||||
|
|
||||||
|
private readonly string apiBase;
|
||||||
|
|
||||||
|
|
||||||
|
public RegistrationPage (string pkgid, string apiBase) : base(apiBase + $"/registration/{pkgid}/index.json")
|
||||||
|
{
|
||||||
|
Parent = apiBase + $"/registration/{pkgid}/index.json";
|
||||||
|
this.items = new List<RegistrationLeaf>();
|
||||||
|
this.pkgid = pkgid;
|
||||||
|
this.apiBase = apiBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegistrationPage(string pkgid, string apiBase, IEnumerable<PackageVersion> versions) : this(pkgid, apiBase)
|
||||||
|
{
|
||||||
|
AddVersionRange(versions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetPackageId()
|
||||||
|
{
|
||||||
|
return pkgid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The array of registration leaves and their associate metadata
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
[JsonProperty("items")]
|
||||||
|
|
||||||
|
public RegistrationLeaf[] Items { get => items.ToArray(); }
|
||||||
|
|
||||||
|
public void AddVersionRange(IEnumerable<PackageVersion> vitems)
|
||||||
|
{
|
||||||
|
if (vitems.Count() == 0) return;
|
||||||
|
NuGetVersion upper = null;
|
||||||
|
NuGetVersion lower = null;
|
||||||
|
PackageVersion latest = null;
|
||||||
|
if (Lower!=null) lower = new NuGetVersion(Lower);
|
||||||
|
if (Upper!=null) upper = new NuGetVersion(Upper);
|
||||||
|
|
||||||
|
// Assert.True(items.All(p=>p.Id == id));
|
||||||
|
long commitMax = 0;
|
||||||
|
foreach (var p in vitems)
|
||||||
|
{
|
||||||
|
if (p.LatestCommit==null) continue;
|
||||||
|
var pkg = p.ToPackage(apiBase);
|
||||||
|
if (items.Contains(pkg)) 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)
|
||||||
|
{
|
||||||
|
latest = p;
|
||||||
|
}
|
||||||
|
items.Add(pkg);
|
||||||
|
}
|
||||||
|
Upper = upper?.ToFullString() ?? lower?.ToFullString();
|
||||||
|
Lower = lower?.ToFullString() ?? upper?.ToFullString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The highest SemVer 2.0.0 version in the page (inclusive)
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
[JsonProperty("upper"), JsonRequired]
|
||||||
|
public string Upper { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// The lowest SemVer 2.0.0 version in the page (inclusive)
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
[JsonProperty("lower"), JsonRequired]
|
||||||
|
public string Lower { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The URL to the registration index
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
[JsonProperty("parent")]
|
||||||
|
public string Parent { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("count")]
|
||||||
|
public int Count { get => items.Count; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
namespace isnd.Data.Catalog
|
||||||
|
{
|
||||||
|
public class Deprecation
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Legacy The package is no longer maintained
|
||||||
|
CriticalBugs The package has bugs which make it unsuitable for usage
|
||||||
|
Other The package is deprecated due to a reason not on this list
|
||||||
|
*/
|
||||||
|
public string[] reasons { get; set; } // array of strings yes The reasons why the package was deprecated
|
||||||
|
public string message { get; set; } // The additional details about this deprecation
|
||||||
|
public AlternatePackage alternatePackage { get; set; } // object no The alternate package that should be used instead
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,237 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
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;
|
||||||
|
using NuGet.Protocol.Core.Types;
|
||||||
|
using NuGet.Protocol;
|
||||||
|
using NuGet.Packaging;
|
||||||
|
using NuGet.Packaging.Core;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using isnd.Entities;
|
||||||
|
|
||||||
|
namespace isnd.Data.Catalog
|
||||||
|
{
|
||||||
|
public class PackageDetails : Permalink, IObject, IPackageSearchMetadata
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a catalog entry
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pkg">package id</param>
|
||||||
|
/// <param name="apiBase">api Base</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public PackageDetails(PackageVersion pkg, string apiBase): base( apiBase + ApiConfig.Registration + "/" + pkg.PackageId + "/" + pkg.FullString + ".json")
|
||||||
|
{
|
||||||
|
Title = PackageId = pkg.Package.Id;
|
||||||
|
Version = pkg.FullString;
|
||||||
|
Authors = $"{pkg.Package.Owner.FullName} <${pkg.Package.Owner.Email}>";
|
||||||
|
packageContent = apiBase + pkg.NugetLink;
|
||||||
|
CommitId = pkg.CommitId;
|
||||||
|
Published = CommitTimeStamp = pkg.LatestCommit.CommitTimeStamp;
|
||||||
|
IsListed = !pkg.IsDeleted && pkg.Package.Public;
|
||||||
|
if (pkg.DependencyGroups!=null)
|
||||||
|
{
|
||||||
|
DependencySets = pkg.DependencyGroups.ToDepSetInfo();
|
||||||
|
|
||||||
|
}
|
||||||
|
PackageDetailsUrl = new Uri(this.id);
|
||||||
|
|
||||||
|
// TODO Licence Project Urls, Summary, Title, Owners, etc ...
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty("@type")]
|
||||||
|
public string[] RefType { get; protected set; } = new string[] { "PackageDetails" };
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="apiBase"></param>
|
||||||
|
/// <param name="pkgId"></param>
|
||||||
|
/// <param name="pkgVersionString"></param>
|
||||||
|
/// <param name="commitId"></param>
|
||||||
|
/// <param name="commitTimeStamp"></param>
|
||||||
|
/// <param name="authors"></param>
|
||||||
|
/// <param name="deprecation"></param>
|
||||||
|
/// <param name="description"></param>
|
||||||
|
/// <param name="iconUrl"></param>
|
||||||
|
/// <param name="language"></param>
|
||||||
|
/// <param name="licenseUrl"></param>
|
||||||
|
/// <param name="licenseExpression"></param>
|
||||||
|
/// <param name="minClientVersion"></param>
|
||||||
|
/// <param name="projectUrl"></param>
|
||||||
|
/// <param name="requireLicenseAcceptance"></param>
|
||||||
|
/// <param name="summary"></param>
|
||||||
|
/// <param name="tags"></param>
|
||||||
|
/// <param name="title"></param>
|
||||||
|
/// <param name="packageContent"></param>
|
||||||
|
/// <param name="version"></param>
|
||||||
|
/// <param name="identity"></param>
|
||||||
|
/// <param name="readmeUrl"></param>
|
||||||
|
/// <param name="reportAbuseUrl"></param>
|
||||||
|
/// <param name="packageDetailsUrl"></param>
|
||||||
|
/// <param name="owners"></param>
|
||||||
|
/// <param name="isListed"></param>
|
||||||
|
/// <param name="prefixReserved"></param>
|
||||||
|
/// <param name="licenseMetadata"></param>
|
||||||
|
public PackageDetails(string apiBase, string pkgId, string pkgVersionString, string commitId, DateTimeOffset commitTimeStamp, string authors, Deprecation deprecation, string description, Uri iconUrl, string language, Uri licenseUrl, string licenseExpression, string minClientVersion, Uri projectUrl, bool requireLicenseAcceptance, string summary, string tags, string title, string packageContent, string version, PackageIdentity identity, Uri readmeUrl, Uri reportAbuseUrl, Uri packageDetailsUrl, string owners, bool isListed, bool prefixReserved, LicenseMetadata licenseMetadata)
|
||||||
|
: base( apiBase + ApiConfig.Registration + "/" + pkgId + "/" + pkgVersionString + ".json")
|
||||||
|
{
|
||||||
|
this.CommitId = commitId;
|
||||||
|
this.CommitTimeStamp = commitTimeStamp;
|
||||||
|
this.Authors = authors;
|
||||||
|
this.deprecation = deprecation;
|
||||||
|
this.Description = description;
|
||||||
|
this.IconUrl = iconUrl;
|
||||||
|
this.language = language;
|
||||||
|
this.LicenseUrl = licenseUrl;
|
||||||
|
this.licenseExpression = licenseExpression;
|
||||||
|
this.minClientVersion = minClientVersion;
|
||||||
|
this.ProjectUrl = projectUrl;
|
||||||
|
this.RequireLicenseAcceptance = requireLicenseAcceptance;
|
||||||
|
this.Summary = summary;
|
||||||
|
this.Tags = tags;
|
||||||
|
this.Title = title;
|
||||||
|
this.packageContent = packageContent;
|
||||||
|
this.Version = version;
|
||||||
|
this.Identity = identity;
|
||||||
|
this.ReadmeUrl = readmeUrl;
|
||||||
|
this.ReportAbuseUrl = reportAbuseUrl;
|
||||||
|
this.PackageDetailsUrl = packageDetailsUrl;
|
||||||
|
this.Owners = owners;
|
||||||
|
this.IsListed = isListed;
|
||||||
|
this.PrefixReserved = prefixReserved;
|
||||||
|
this.LicenseMetadata = licenseMetadata;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty("commitId")]
|
||||||
|
public string CommitId { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("commitTimeStamp")]
|
||||||
|
public DateTimeOffset CommitTimeStamp { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Authors
|
||||||
|
/// </summary>
|
||||||
|
/// <value>string or array of strings</value>
|
||||||
|
[JsonProperty("authors")]
|
||||||
|
public string Authors { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The deprecation associated with the package
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public Deprecation deprecation { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("description")]
|
||||||
|
public string Description { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("iconUrl")]
|
||||||
|
public Uri IconUrl { get; set; }
|
||||||
|
|
||||||
|
public string language { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty("licenseUrl")]
|
||||||
|
public Uri LicenseUrl { get; set; }
|
||||||
|
|
||||||
|
public string licenseExpression { get; set; }
|
||||||
|
|
||||||
|
public string minClientVersion { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("projectUrl")]
|
||||||
|
public Uri ProjectUrl { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty("requireLicenseAcceptance")]
|
||||||
|
public bool RequireLicenseAcceptance { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("summary")]
|
||||||
|
public string Summary { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The tags
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
[JsonProperty("tags")]
|
||||||
|
public string Tags { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("title")]
|
||||||
|
public string Title { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The security vulnerabilities of the package
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public IEnumerable<PackageVulnerabilityMetadata> Vulnerabilities { get; }
|
||||||
|
|
||||||
|
public string packageContent { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A string containing a ISO 8601 timestamp of when the package was published
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
[JsonProperty("published")]
|
||||||
|
public DateTimeOffset? Published { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The full version string after normalization
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
[Required,JsonRequired]
|
||||||
|
[JsonProperty("version")]
|
||||||
|
public string Version { get; set; }
|
||||||
|
|
||||||
|
[Required,JsonRequired]
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public string PackageId { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public long? DownloadCount { get; set; }
|
||||||
|
|
||||||
|
public PackageIdentity Identity{ get; set; }
|
||||||
|
|
||||||
|
public Uri ReadmeUrl { get; set; }
|
||||||
|
|
||||||
|
public Uri ReportAbuseUrl { get; set; }
|
||||||
|
|
||||||
|
public Uri PackageDetailsUrl { get; set; }
|
||||||
|
|
||||||
|
public string Owners { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("isListed")]
|
||||||
|
public bool IsListed { get; set; }
|
||||||
|
|
||||||
|
public bool PrefixReserved { get; set; }
|
||||||
|
|
||||||
|
public LicenseMetadata LicenseMetadata { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<PackageDependencyGroupInfo> DependencySets {get; set;}
|
||||||
|
|
||||||
|
IEnumerable<NuGet.Packaging.PackageDependencyGroup> IPackageSearchMetadata.DependencySets => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public Task<PackageDeprecationMetadata> GetDeprecationMetadataAsync()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<IEnumerable<VersionInfo>> GetVersionsAsync()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PackageDependencyGroupInfo
|
||||||
|
{
|
||||||
|
private PackageDependencyGroup group;
|
||||||
|
|
||||||
|
public PackageDependencyGroupInfo(PackageDependencyGroup group)
|
||||||
|
{
|
||||||
|
this.group = group;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
using isnd.Data.Packages;
|
||||||
|
using isnd.Entities;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace isnd.Data.Catalog
|
||||||
|
{
|
||||||
|
public class PackageRegistration : Permalink
|
||||||
|
{
|
||||||
|
|
||||||
|
public PackageRegistration(string url) : base(url)
|
||||||
|
{
|
||||||
|
Items = new List<RegistrationPage>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageRegistration(string apiBase, string pkgId, IEnumerable<PackageVersion> versions) : base($"{apiBase}{ApiConfig.Registration}/{pkgId}/index.json")
|
||||||
|
{
|
||||||
|
Items = new List<RegistrationPage>
|
||||||
|
{
|
||||||
|
new RegistrationPage(pkgId, apiBase, versions)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty("count")]
|
||||||
|
public int Count { get => Items.Count; }
|
||||||
|
|
||||||
|
[JsonProperty("items")]
|
||||||
|
public List<RegistrationPage> Items { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using isnd.Data.Packages;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace isnd.Data.Catalog
|
||||||
|
{
|
||||||
|
public class PackageRegistrationQuery
|
||||||
|
{
|
||||||
|
public PackageRegistrationQuery()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty("query")]
|
||||||
|
public string Query { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("prerelease")]
|
||||||
|
public bool Prerelease { get; set; } = true;
|
||||||
|
[JsonProperty("skip")]
|
||||||
|
|
||||||
|
public int Skip { get; set; } = 0;
|
||||||
|
[JsonProperty("take")]
|
||||||
|
|
||||||
|
public int Take { get; set; } = 25;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using isnd.Entities;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using isn.abst;
|
||||||
|
|
||||||
|
namespace isnd.Data.Catalog
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Hosts a catalog entry,
|
||||||
|
/// the atomic content reference
|
||||||
|
/// </summary>
|
||||||
|
public class RegistrationLeaf
|
||||||
|
{
|
||||||
|
public RegistrationLeaf(string apiBase, string pkgId, string fullVersionString, PackageDetails entry)
|
||||||
|
{
|
||||||
|
|
||||||
|
this.registration = apiBase + ApiConfig.Registration + "/" + pkgId + "/" + fullVersionString + ".json";
|
||||||
|
Id = registration;
|
||||||
|
this.PackageContent = apiBase + ApiConfig.Nuget + "/" + pkgId + "/" + fullVersionString
|
||||||
|
+ "/" + pkgId + "-" + fullVersionString + "." + Constants.PacketFileExtension;
|
||||||
|
Entry = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@id string yes
|
||||||
|
catalogEntry object yes
|
||||||
|
packageContent string yes
|
||||||
|
*/
|
||||||
|
/// <summary>
|
||||||
|
/// The URL to the registration leaf
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
[JsonProperty("@id")]
|
||||||
|
[Key][Required]
|
||||||
|
[StringLength(1024)]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The catalog entry containing the package metadata
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
[JsonProperty("catalogEntry")]
|
||||||
|
public PackageDetails Entry { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The URL to the package content (.nupkg)
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
[JsonProperty("packageContent")]
|
||||||
|
public string PackageContent { get; set; }
|
||||||
|
|
||||||
|
public string registration { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
namespace isnd.Data.Catalog
|
||||||
|
{
|
||||||
|
public class Vulnerabilitie
|
||||||
|
{
|
||||||
|
public string advisoryUrl { get; set; } // string yes Location of security advisory for the package
|
||||||
|
public string severity { get; set; } // string yes Severity of advisory: "0" = Low, "1" = Moderate, "2" = High, "3" = Critical
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using isnd.Data.Packages;
|
||||||
|
using isnd.Data.Packages.Catalog;
|
||||||
|
|
||||||
|
namespace isnd.Data.Historic
|
||||||
|
{
|
||||||
|
public class PackageVersionCommit
|
||||||
|
{
|
||||||
|
public long CommitId { get; set; }
|
||||||
|
|
||||||
|
[StringLength(1024)]
|
||||||
|
public string PackageId { get; set; }
|
||||||
|
|
||||||
|
[StringLength(256)]
|
||||||
|
public string FullString { get; set; }
|
||||||
|
|
||||||
|
[StringLength(256)]
|
||||||
|
|
||||||
|
public string PackageType { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("CommitId")]
|
||||||
|
public virtual Commit Commit { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("PackageId")]
|
||||||
|
public virtual Package Package { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("PackageId,FullString,PackageType")]
|
||||||
|
public virtual PackageVersion PackageVersion { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace isnd.Interfaces
|
||||||
|
{
|
||||||
|
public interface IObject
|
||||||
|
|
||||||
|
{
|
||||||
|
[JsonProperty("@type")]
|
||||||
|
public string Type { get => GetType().Name; }
|
||||||
|
|
||||||
|
[JsonProperty("commitId")]
|
||||||
|
string CommitId { get; }
|
||||||
|
|
||||||
|
[JsonProperty("commitTimeStamp")]
|
||||||
|
DateTimeOffset CommitTimeStamp { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using isnd.Interfaces;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace isnd.Data.Packages.Catalog
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An presence of package in a catalog,
|
||||||
|
/// for availability, or deletion,
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public class PackageDetails : IObject
|
||||||
|
{
|
||||||
|
|
||||||
|
[JsonProperty("@id")]
|
||||||
|
public string RefId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reference type :
|
||||||
|
/// nuget:PackageDetails vs nuget:PackageDelete
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
[JsonProperty("@type")]
|
||||||
|
public string RefType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The NuGet Id
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
[JsonProperty("nuget:id")]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The NuGet version
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
|
||||||
|
[JsonProperty("nuget:version")]
|
||||||
|
public string Version { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("commitId")]
|
||||||
|
public string CommitId { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("CommitId"), JsonIgnore]
|
||||||
|
public virtual Commit LastCommit { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("commitTimeStamp")]
|
||||||
|
public DateTimeOffset CommitTimeStamp { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using isnd.Interfaces;
|
||||||
|
|
||||||
|
namespace isnd.Data.Packages.Catalog
|
||||||
|
{
|
||||||
|
public class PackageEntry : IObject
|
||||||
|
{
|
||||||
|
public string CommitId => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public DateTimeOffset CommitTimeStamp => throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using isnd.Interfaces;
|
||||||
|
|
||||||
|
namespace isnd.Data.Packages
|
||||||
|
{
|
||||||
|
public enum PackageAction
|
||||||
|
{
|
||||||
|
DeletePackage,
|
||||||
|
PublishPackage
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Commit : IObject
|
||||||
|
{
|
||||||
|
[Key,
|
||||||
|
DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
|
[JsonIgnore]
|
||||||
|
public long Id { get; set; }
|
||||||
|
|
||||||
|
[Required][JsonIgnore]
|
||||||
|
public DateTimeOffset TimeStamp{ get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public PackageAction Action { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public string CommitId { get => Id.ToString(); }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public DateTimeOffset CommitTimeStamp { get => TimeStamp; }
|
||||||
|
|
||||||
|
[ForeignKey("CommitNId")]
|
||||||
|
|
||||||
|
public virtual List<PackageVersion> Versions { get; set; }
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue