Compare commits

29 Commits

Author SHA1 Message Date
301a276a7b Find package versions ignoring character case 2025-03-04 14:28:29 +00:00
bc1464db7f Web search result fixed 2025-02-01 19:44:31 +00:00
913f2ae5dd Layout 2024-11-03 16:20:43 +00:00
27ad3841a0 Fixes he layout 2024-11-03 16:10:03 +00:00
a6f9d974d3 Licence 2024-11-03 13:30:21 +00:00
a3d3e51259 uodated : usefull 2024-11-03 11:12:48 +00:00
753f54dad0 Home index 2024-11-02 15:49:26 +00:00
72ecf30458 repo cleanup 2024-10-20 19:54:36 +01:00
5f1dca3d61 dotnet package resolution 2024-10-20 19:47:49 +01:00
c615886a4c unit testing 2024-10-19 13:25:58 +01:00
2b45e421dd GetMetaData OK 2024-10-09 23:19:38 +01:00
7ca465d4a9 JQuery version bump 2024-07-28 14:07:06 +01:00
8532b81638 WIP package resolution 2024-07-19 10:21:25 +02:00
01405abdf2 Package deletion and types 2024-04-28 15:44:12 +01:00
62a8bf27cb Error Page 2024-04-28 15:43:10 +01:00
9c9ee6cc4c trying with isn.abst 2024-04-22 21:51:06 +01:00
3af05fc034 dependencies 2024-04-16 22:30:39 +01:00
04a467dd83 registration and detail url's 2024-03-31 15:59:43 +01:00
96f91c3ba0 net-8, localization, privacy, and js ref's 2024-03-30 09:45:17 +00:00
aeecc524a4 WIP /search 2024-03-24 16:53:12 +00:00
e229439174 Fixes the registration page index 2024-03-16 14:33:10 +00:00
c6c52a48c4 some details 2024-03-11 20:55:52 +00:00
8656bce151 fixes the catalog page 2024-03-11 01:02:11 +00:00
d6180aa154 REORG 2024-03-10 20:10:05 +00:00
89e1b5a235 Testing the push method (TODO coherence between return code a physical result) 2024-03-09 21:43:56 +00:00
e69462999e Cx strings contains user secrets ... 2024-03-09 16:13:30 +00:00
e1a012e15b orthograph 2024-02-12 02:45:47 +00:00
16258d1c33 version bumps 2024-02-12 02:22:10 +00:00
019d858ac2 fixes the chown 2024-02-12 02:21:50 +00:00
1638 changed files with 233130 additions and 3434 deletions

7
.gitignore vendored
View File

@ -6,14 +6,8 @@
/src/isn/.vscode/
/test/isnd.tests/obj/
/test/isnd.tests/bin/
/packages/
bower_components/
/test/isn.tests/bin
/test/isn.tests/obj/
appsettings.Testing.json
appsettings.Development.json
/wwwroot/.sass-cache/
/src/isnd/wwwroot/.sass-cache/
/src/isn.abst/bin
/src/isn.abst/obj
/src/isnd/packages/
@ -23,4 +17,5 @@ appsettings.Development.json
/artifacts/
/.vs/
/.vscode/
appsettings.Development.json

52
.vscode/tasks.json vendored
View File

@ -1,19 +1,6 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "restore",
"command": "dotnet",
"type": "process",
"args": [
"restore",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary",
"--ignore-failed-sources"
],
"problemMatcher": "$msCompile",
"group": "build"
},
{
"label": "build",
"command": "dotnet",
@ -46,21 +33,6 @@
"dependsOn":["build"],
"group": "test"
},
{
"label": "buildcli",
"command": "msbuild",
"type": "process",
"args": [
"src/isn",
"/p:Configuration=Debug",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary",
"/restore"
],
"problemMatcher": "$msCompile",
"group": "build"
},
{
"label": "publish",
"command": "dotnet",
@ -79,31 +51,13 @@
},
"group": "none"
},
{
"label": "monopublish",
"command": "msbuild",
"type": "process",
"args": [
"/t:publish",
"/p:TargetFramework=netcoreapp2.1;PublishDir=${workspaceFolder}/artiffacts;RuntimeIdentifier=linux-x64",
],
"problemMatcher": "$msCompile"
},
{
"label": "copyTestConfig",
"command": "dotnet",
"type": "process",
"args": [ "build", "/t:CopyTestConfig" ],
"group": "test"
},
{
"label": "test",
"command": "dotnet",
"type": "process",
"options": {
"env": {
"ASPNETCORE_ENVIRONMENT": "Testing"
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"args": [
@ -112,7 +66,7 @@
"--logger:xunit"
],
"problemMatcher": "$msCompile",
"dependsOn": [ "build", "copyTestConfig"],
"dependsOn": [ "build"],
"group": "test"
},
{
@ -130,7 +84,7 @@
}
},
"problemMatcher": "$msCompile",
"group": "test"
"group": "none"
}
]
}

View File

@ -1,5 +0,0 @@
mode: Mainline
branches: {}
ignore:
sha: []
merge-message-formats: {}

View File

@ -1,6 +1,6 @@
CONFIGURATION=Debug
TARGETFV=net7.0
TARGETFV=net8.0
all: build-isn build-isnd
@ -23,10 +23,24 @@ 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
dotnet publish -c Release -f net7.0 src/isnd
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/net7.0/publish/* /srv/www/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

View File

@ -1,6 +1,6 @@
# ISN
En cours de developement, le détail du paquet n'est toujours pas fourni en API.
Hébergement de paquets logiciels Nuget, fournissant une implémentation minimale de l'API Nuget V3
## Usage
@ -20,21 +20,22 @@ wget http://localhost:5000/package/index.json?q=your&prerelease=true&semVerLevel
### Compilation
Depuis le dossier de la solution, compiler la solution :
Dans le dossier de la solution, compiler la solution :
````bash
dotnet build /restore -c Release
dotnet publish -c Release
dotnet publish -c Release src/isnd
````
### Déploiement du serveur
Commençont par la livraison initiale, aujourd'hui :
La livraison initiale, aujourd'hui :
````bash
sudo mkdir -p /srv/www/isnd
sudo cp -a src/isnd/bin/Release/net7.0/publish/* /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
````
@ -43,13 +44,13 @@ son utilisateur, et le droit de créer des tables (ce dernier droit pourrait exp
Il faudra éditer la configuration pour indiquer :
* la connextion à une base de donnée Postresgql, sous la forme :
* 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>;"`
* la connection au serveur de messagerie,
* l'URL du ou des sites à propulser,
* Les autres détails.
* 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 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 :
@ -75,15 +76,25 @@ 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 net7.0 src/isnd
dotnet publish -c Release -f net8.0 src/isnd
# MAJ du serveur
sudo systemctl stop isnd
sudo cp -a src/isnd/bin/Release/net7.0/publish/* /srv/www/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/net7.0/* /usr/local/lib/isn
sudo chown -R root.root /usr/local/lib/isn
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
````

View File

@ -1,28 +0,0 @@
[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/
# If using Unix socket: tells systemd to create the /run/gitea folder, which will contain the gitea.sock file
# (manually creating /run/gitea doesn't work, because it would not persist across reboots)
#RuntimeDirectory=gitea
ExecStart=/srv/www/isnd/isnd
Restart=always
Environment=HOME=/srv/www/isnd
#CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.target

View File

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

View File

@ -1,2 +0,0 @@
nuget install -Verbosity detailed -Source http://localhost:5000/index.json -Prerelease Yavsc.Abstract
nuget locals all -clear

View File

@ -1,4 +0,0 @@
= URL's
<http://localhost:5000/v3.4.0/registration/yavsc.abstract/index.json>

View File

@ -1,30 +1,41 @@
{
"version": 1,
"isRoot": true,
"tools": {
"codecov.tool": {
"version": "1.13.0",
"commands": [
"codecov"
]
},
"gitversion.tool": {
"version": "5.10.1",
"commands": [
"dotnet-gitversion"
]
},
"gitreleasemanager.tool": {
"version": "0.13.0",
"commands": [
"dotnet-gitreleasemanager"
]
},
"Wyam2.Tool": {
"version": "3.0.0-rc3",
"commands": [
"wyam2"
]
}
"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
}
}
}
}

27
gitversion.json Normal file
View File

@ -0,0 +1,27 @@
{
"AssemblySemFileVer": "1.1.1.0",
"AssemblySemVer": "1.1.1.0",
"BranchName": "main",
"BuildMetaData": null,
"CommitDate": "2024-10-09",
"CommitsSinceVersionSource": 19,
"EscapedBranchName": "main",
"FullBuildMetaData": "Branch.main.Sha.2b45e421dda285b73bf7eb3387915030cd751b88",
"FullSemVer": "1.1.1-19",
"InformationalVersion": "1.1.1-19+Branch.main.Sha.2b45e421dda285b73bf7eb3387915030cd751b88",
"Major": 1,
"MajorMinorPatch": "1.1.1",
"Minor": 1,
"Patch": 1,
"PreReleaseLabel": "",
"PreReleaseLabelWithDash": "",
"PreReleaseNumber": 19,
"PreReleaseTag": "19",
"PreReleaseTagWithDash": "-19",
"SemVer": "1.1.1-19",
"Sha": "2b45e421dda285b73bf7eb3387915030cd751b88",
"ShortSha": "2b45e42",
"UncommittedChanges": 20,
"VersionSourceSha": "72839e8251297935a4ab138a99152733f07a23f2",
"WeightedPreReleaseNumber": 55019
}

View File

@ -1,12 +0,0 @@
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" ;

View File

@ -1,22 +0,0 @@
{
"dotnet": {
"enabled": false
},
"msbuild": {
"enabled": true
},
"Dnx": {
"enabled": false
},
"Script": {
"enabled": false
},
"fileOptions": {
"systemExcludeSearchPatterns": [
"**/bin/**/*",
"**/obj/**/*",
"**/node_modules/**/*"
],
"userExcludeSearchPatterns": []
}
}

35
src/.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,35 @@
{
"version": "0.2.0",
"configurations": [
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md.
"name": ".NET Core Launch (web)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/isnd/bin/Debug/net8.0/isnd.dll",
"args": [],
"cwd": "${workspaceFolder}/isnd",
"stopAtEntry": false,
// 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"
}
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
}
]
}

41
src/.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,41 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/isnd/isnd.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/isnd/isnd.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/isnd/isnd.csproj"
],
"problemMatcher": "$msCompile"
}
]
}

11
src/Directory.Build.props Normal file
View File

@ -0,0 +1,11 @@
<Project>
<PropertyGroup>
<Version>1.0.8</Version>
<Authors>paul</Authors>
<Copyright>WFPL</Copyright>
<PackageLicenseExpression></PackageLicenseExpression>
<ProjectUrl></ProjectUrl>
<RepositoryUrl></RepositoryUrl>
<RepositoryType>git</RepositoryType>
</PropertyGroup>
</Project>

View File

@ -1,3 +1,4 @@
using System;
using isn.abst;
namespace isnd.Entities
@ -11,10 +12,13 @@ namespace isnd.Entities
public const string AutoComplete = "/autocomplete";
public const string Registration = "/registration";
public const string Nuspec = "/nuspec";
public const string Content = "/content";
public const string ContentBase = "/content";
public const string Nuget = "/nuget";
public const string Find = "/index/FindPackagesById()"; // /FindPackagesById()?id='isn.abst'&semVerLevel=2.0.0
public const string PackageDetailUriTemplate = Package+"/{id}/{version}";
[Obsolete("use the V3 search")]
public const string V2Find = "/v2/FindPackagesById()"; // /FindPackagesById()??$filter=IsLatestVersion&$orderby=Version desc&$top=1&id='isn.abst'
}
}

View File

@ -2,8 +2,8 @@ namespace isn.abst
{
public static class Constants
{
public const string PaquetFileEstension = "nupkg";
public const string SpecFileEstension = "nuspec";
public const string PacketFileExtension = "nupkg";
public const string SpecFileExtension = "nuspec";
public const string ApiVersionPrefix = "/v3";
}
}

View File

@ -4,6 +4,11 @@ namespace isnd.Data.Catalog
{
public abstract class Permalink
{
public Permalink(string id)
{
Type = GetType().Name;
this.id = id;
}
public Permalink(string id, string type)
{
@ -11,19 +16,14 @@ namespace isnd.Data.Catalog
this.id = id;
}
public Permalink(string id)
{
Type = GetType().Name;
this.id = id;
}
[JsonProperty("@type")]
public virtual string Type { get; set; }
[JsonProperty("@id")]
public string Id { get => GetId(); }
private readonly string id;
public string Id { get => id; }
protected string id;
public string GetId() { return id; }

View File

@ -1,14 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackageVersion>1.0.1</PackageVersion>
<Version>1.0.7</Version>
<TargetFrameworks>net7.0</TargetFrameworks>
<NoWarn>NETSDK1138</NoWarn>
<AssemblyVersion>1.0.7.0</AssemblyVersion>
<FileVersion>1.0.7.0</FileVersion>
<InformationalVersion>1.0.7+Branch.main.Sha.3695c1742965d93eba0ad851656cfaa3e44ba327</InformationalVersion>
</PropertyGroup>
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="11.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
</Project>

View File

@ -1,47 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace isn
{
public interface IDataProtector
{
string Protect(string data);
string UnProtect(string data);
}
public class DefaultDataProtector : IDataProtector
{
private byte delta = 145;
public DefaultDataProtector()
{
}
public string Protect(string data)
{
List<Byte> protd = new List<byte>();
StringBuilder sb = new StringBuilder();
foreach (byte c in Encoding.UTF8.GetBytes(data))
{
protd.Add((byte) (c ^ delta));
}
return System.Convert.ToBase64String(protd.ToArray());
}
public string UnProtect(string data)
{
if (data==null) return null;
StringBuilder sb = new StringBuilder();
List<byte> unps = new List<byte>();
foreach (byte c in System.Convert.FromBase64CharArray(data.ToCharArray(),0,data.Length))
{
unps.Add((byte) (c ^ delta));
}
return Encoding.UTF8.GetString(unps.ToArray());
}
}
}

View File

@ -1,9 +0,0 @@
namespace isn
{
public class IsnSourceSettings
{
internal string Source { get; set; }
internal string[] Keys { get; set; }
}
}

View File

@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Mono.Options;
using Newtonsoft.Json;
@ -16,16 +18,17 @@ namespace isn
if (cfgSettingIf.Exists)
{
var json = File.ReadAllText(cfgSettingIf.FullName);
settings = JsonConvert.DeserializeObject<Settings>(json);
if (settings.DefaultSourceKey == null)
{
Settings.DefaultSourceKey = settings.Sources.Keys.FirstOrDefault();
}
CurrentSource = settings.DefaultSourceKey;
Settings = JsonConvert.DeserializeObject<Settings>(json);
CurrentSource = Settings.DefaultSourceKey;
}
if (Settings==null)
{
Settings= Settings.Create();
}
}
static readonly OptionSet storeoptions = new OptionSet {
{ "s|source=", "use source", val => CurrentSource ??= val },
{ "s|source=", "use source", val => Settings.CurrentSourceKey ??= val },
{ "h|help", "show this message and exit", h => shouldShowPushHelp = h != null },
};
@ -42,11 +45,9 @@ namespace isn
{ "v|version", "show soft version info and exit", h => shouldShowVersion = h != null }
};
static string apiKey;
static readonly OptionSet pushoptions = new OptionSet {
{ "k|api-key=", "use api key", val => apiKey = apiKey ?? val },
{ "s|source=", "use source", val => CurrentSource = CurrentSource ?? val },
{ "k|api-key=", "use api key", val => Settings.CurrentSource.SetApiKey(val)},
{ "s|source=", "use source", val => Settings.CurrentSourceKey = val },
{ "h|help", "show this message and exit", h => shouldShowPushHelp = h != null },
};
static readonly OptionSet sourceoptions = new OptionSet {
@ -62,30 +63,19 @@ namespace isn
private static bool shouldShowSourceHelp;
private static bool shouldShowPushHelp;
static Settings settings = null;
public static Settings Settings
{
get
{
if (settings == null)
LoadConfig();
if (settings == null)
{
settings = new Settings
{
DataProtectionTitle = "isn",
Sources = new Dictionary<string, SourceSettings>()
};
}
return settings;
}
get; set;
}
public static string CurrentSource { get => Settings.CurrentSourceKey; set => Settings.CurrentSourceKey = value; }
static int Main(string[] args)
{
LoadConfig();
var commandSet = new CommandSet("isn");
var srclst = new Command("list")
{
@ -217,7 +207,6 @@ namespace isn
Console.WriteLine("isn version " + GitVersionInformation.AssemblySemFileVer);
}
return commandSet.Run(args);
}
}
}

View File

@ -1,46 +1,57 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Newtonsoft.Json;
namespace isn
{
public class SourceSettings
{
/// <summary>
/// Protected API Key
/// </summary>
/// <value></value>
public string ApiKey { get; set; }
public string ApiKey { get; set; }
/// <summary>
/// Key alias
/// </summary>
/// <value></value>
public string Alias { get; set; }
public string Url { get; set; }
public SourceSettings()
{
}
public string GetClearApiKey()
{
return Protector.UnProtect(ApiKey);
return ApiKey;
}
public void SetApiKey(string key)
{
ApiKey = Protector.Protect(key);
ApiKey = key;
}
public static IDataProtector Protector { get; set; } = new DefaultDataProtector();
}
public class Settings
{
public string DataProtectionTitle { get; set; }
public Dictionary<string, SourceSettings> Sources { get; set; }
private Settings()
{
public bool AutoUpdateApiKey { get; set; } = false;
}
public static Settings Create()
{
return new Settings {
Sources = new Dictionary<string, SourceSettings>()
};
}
public Dictionary<string, SourceSettings> Sources { get; set; }
private string defSourceKey;
@ -53,29 +64,26 @@ namespace isn
get => defSourceKey;
set
{
if (!Sources.ContainsKey(value))
{
Sources[value]=new SourceSettings
{
Alias = defSourceKey
};
}
defSourceKey = value;
}
}
string currentSourceKey;
[JsonIgnore, NotMapped]
public string CurrentSourceKey
public string CurrentSourceKey {get; set;}
[JsonIgnore, NotMapped]
public SourceSettings CurrentSource
{
get {
return currentSourceKey;
}
set{
if (!Sources.ContainsKey(value))
throw new InvalidOperationException($"source is invalid ({value})");
currentSourceKey = value;
get
{
if (CurrentSourceKey==null) return null;
if (!Sources.ContainsKey(CurrentSourceKey))
{
Sources.Add(CurrentSourceKey, new SourceSettings());
}
return Sources[CurrentSourceKey];
}
}
}

View File

@ -17,7 +17,7 @@ namespace isn
this.settings = settings;
}
public PushReport Run(string pkg, string source, string apikey)
public PushReport Run(string pkg, string source, string apiKey)
{
var resources = SourceHelpers.GetServerResources(source);
@ -33,25 +33,30 @@ namespace isn
var report = new PushReport
{
PkgName = fi.Name,
Message = "Le fichier n'existe pas : " + fi.FullName
Message = "The package does not exist : " + fi.FullName
};
return report;
}
using (var client = new HttpClient())
using (var client = new HttpClient(
new HttpClientHandler
{
AllowAutoRedirect = false
}
))
try
{
return client.UploadFilesToServer(new Uri(pubRes.Id), fi, settings.Sources[source].GetClearApiKey());
return client.UploadFilesToServer(new Uri(pubRes.Id), fi, settings.Sources[source].ApiKey);
}
catch (HttpRequestException hrex)
catch (HttpRequestException httpEx)
{
var report = new PushReport
{
PkgName = fi.Name,
Message = "HttpRequest: " + hrex.Message,
StackTrace = hrex.StackTrace,
StatusCode = hrex.HResult.ToString()
Message = "HttpRequest: " + httpEx.Message,
StackTrace = httpEx.StackTrace,
StatusCode = httpEx.HResult.ToString()
};
Console.Error.WriteLine(hrex.Message);
Console.Error.WriteLine(httpEx.Message);
return report;
}
catch (Exception ex)

View File

@ -14,11 +14,11 @@ namespace isn
List<PushReport> pushReports = new List<PushReport>();
var cmd = new PushCommand(Settings);
if (CurrentSource == null) throw new InvalidOperationException("source is null");
if (Settings.CurrentSource == null) throw new InvalidOperationException("source is null");
var source = Settings.CurrentSource;
foreach (string pkg in pkgs)
{
var report = cmd.Run(pkg, CurrentSource, apiKey);
var report = cmd.Run(pkg, source.Url, source.ApiKey);
pushReports.Add(report);
}
return pushReports;

View File

@ -16,7 +16,7 @@ namespace isn
{
SourceSettings setting = Settings.Sources[arg];
throw new InvalidOperationException
(setting.Alias);
(setting.Url);
}
throw new NotImplementedException();
}

View File

@ -11,7 +11,7 @@ namespace isn
SourceSettings settings =
Settings.Sources.ContainsKey(arg) ?
Settings.Sources[arg] :
Settings.Sources.Values.FirstOrDefault((s)=> s.Alias == arg) ;
Settings.Sources.Values.FirstOrDefault((s)=> s.Url == arg) ;
if (settings==null) throw new InvalidOperationException(arg);
Settings.DefaultSourceKey = arg;
SaveConfig();

View File

@ -14,7 +14,7 @@ namespace isn
var args = storeoptions.Parse(storeArgs);
if (args.Count != 1)
{
Console.Error.WriteLine("StoreApiKey command takse one and only one argument, the key.");
Console.Error.WriteLine("StoreApiKey command takes only one argument, the key.");
shouldShowPushHelp=true;
}
if (shouldShowPushHelp)
@ -25,7 +25,7 @@ namespace isn
}
else
{
Settings.Sources[Settings.CurrentSourceKey].SetApiKey(args[0]);
Settings.CurrentSource.SetApiKey(args[0]);
SaveConfig();
}
}

View File

@ -1,25 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net7.0</TargetFrameworks>
<TargetFrameworks>net8.0</TargetFrameworks>
<RootNamespace>nuget_cli</RootNamespace>
<UserSecretsId>45b74c62-05bc-4603-95b4-3e80ae2fdf50</UserSecretsId>
<Version>1.0.7</Version>
<PackageVersion>1.0.1</PackageVersion>
<IsPackable>true</IsPackable>
<PackageLicenseExpression>WTFPL</PackageLicenseExpression>
<IsTool>true</IsTool>
<NoWarn>NETSDK1138</NoWarn>
<AssemblyVersion>1.0.7.0</AssemblyVersion>
<FileVersion>1.0.7.0</FileVersion>
<InformationalVersion>1.0.7+Branch.main.Sha.3695c1742965d93eba0ad851656cfaa3e44ba327</InformationalVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="7.0.1" />
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="8.0.1" />
<PackageReference Include="Mono.Options" Version="5.3.0" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="unleash.client" Version="1.6.1" />
<PackageReference Include="GitVersion.MsBuild" Version="5.6.10*" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="unleash.client" Version="4.1.13" />
<PackageReference Include="GitVersion.MsBuild" Version="6.0.3" />
<ProjectReference Include="../isn.abst/isn.abst.csproj" />
</ItemGroup>
</Project>

View File

@ -13,6 +13,7 @@ using Microsoft.Extensions.Options;
using isnd.Data;
using isnd.Entities;
using isnd.Data.ApiKeys;
using isnd.Interfaces;
namespace isnd.Controllers
@ -23,17 +24,20 @@ namespace isnd.Controllers
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)
UserManager<ApplicationUser> userManager,
IApiKeyProvider apiKeyProvider
)
{
this.dbContext = dbContext;
this.isndSettings = isndSettingsOptions.Value;
protector = provider.CreateProtector(isndSettings.ProtectionTitle);
_userManager = userManager;
this.apiKeyProvider = apiKeyProvider;
}
[HttpGet]
@ -57,17 +61,17 @@ namespace isnd.Controllers
[HttpPost]
public async Task<ActionResult> Create(CreateModel model)
{
string userid = User.FindFirstValue(ClaimTypes.NameIdentifier);
IQueryable<ApiKey> userKeys = GetUserKeys();
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();
}
ApiKey newKey = new ApiKey { UserId = userid, Name = model.Name,
CreationDate = DateTimeOffset.Now.ToUniversalTime() };
_ = dbContext.ApiKeys.Add(newKey);
_ = await dbContext.SaveChangesAsync();
model.UserId = userId;
ApiKey newKey = await apiKeyProvider.CreateApiKeyAsync(model);
return View("Details", new DetailModel { Name = newKey.Name,
ProtectedValue = protector.Protect(newKey.Id),
ApiKey = newKey });
@ -79,7 +83,6 @@ namespace isnd.Controllers
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]
@ -103,7 +106,7 @@ namespace isnd.Controllers
ApiKey key = await dbContext.ApiKeys.FirstOrDefaultAsync(k => k.Id == id && k.UserId == userid);
if (key == null)
{
ModelState.AddModelError(null, "Key not found");
ModelState.AddModelError("id", "Key not found");
return View();
}
return View("Details", new DetailModel { ApiKey = key, Name = key.Name, ProtectedValue = protector.Protect(key.Id)});

View File

@ -6,6 +6,10 @@ using System.Linq;
using isnd.ViewModels;
using System.Reflection;
using Microsoft.EntityFrameworkCore;
using Microsoft.Build.Logging;
using Microsoft.Extensions.Options;
using isnd.Entities;
using isn.abst;
namespace isnd.Controllers
{
@ -15,14 +19,18 @@ namespace isnd.Controllers
public class HomeController : Controller
{
private readonly ApplicationDbContext _dbContext;
private readonly IsndSettings _isndSettings;
/// <summary>
/// Home controller ctor
/// </summary>
/// <param name="dbContext"></param>
/// <param name="isndSettings"></param>
public HomeController(
ApplicationDbContext dbContext)
ApplicationDbContext dbContext, IOptions<IsndSettings> isndSettings)
{
_dbContext = dbContext;
_isndSettings = isndSettings.Value;
}
public IActionResult Index()
@ -30,7 +38,8 @@ namespace isnd.Controllers
return View(new HomeIndexViewModel{
PkgCount = _dbContext.Packages
.Where(p => p.Versions.Count > 0)
.Count()});
.Count(),
APIUrl = _isndSettings.ExternalUrl + Constants.ApiVersionPrefix + ApiConfig.Index});
}
public IActionResult About()
@ -59,9 +68,9 @@ namespace isnd.Controllers
return View(ViewData);
}
public IActionResult Error()
public IActionResult Error(string id)
{
return View();
return View("Error", id);
}
}
}

View File

@ -33,7 +33,7 @@ namespace isnd.Controllers
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Index)]
public IActionResult ApiIndex()
{
return Ok(new ApiIndexViewModel(packageManager.CatalogBaseUrl){ Version = PackageManager.BASE_API_LEVEL, Resources = resources });
return Ok(new ApiIndexViewModel(packageManager.CatalogBaseUrl + ApiConfig.Index){ Version = PackageManager.BASE_API_LEVEL, Resources = resources });
}
}

View File

@ -0,0 +1,18 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using isnd.Entities;
using isn.abst;
namespace isnd.Controllers
{
public partial class PackagesController
{
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.PackageDetailUriTemplate)]
public async Task<IActionResult> Details(string id, string version)
{
var result = await packageManager.GetPackageDetailsAsync(id, version);
if (result==null) return NotFound();
return Ok(result);
}
}
}

View File

@ -1,13 +1,6 @@
using System.Data.Common;
using System.Linq;
using System.Threading.Tasks;
using isnd.Services;
using isnd.Entities;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using NuGet.Versioning;
using isnd.Data.Packages.Catalog;
using isnd.Data.Catalog;
using isn.abst;
namespace isnd.Controllers
@ -23,7 +16,9 @@ namespace isnd.Controllers
}
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Registration + "/{id}/{version}.json")]
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Registration + "/{id}/{version}.json")]
public async Task<IActionResult> CatalogRegistration(string id, string version)
{
if ("index" == version)
@ -38,8 +33,8 @@ namespace isnd.Controllers
return Ok(index);
}
// return a Package
var leaf = await packageManager.GetCatalogEntryAsync(id, version, null);
// return Package details
var leaf = await packageManager.GetPackageDetailsAsync(id, version, null);
if (null == leaf) return NotFound(new { id, version });
return Ok(leaf);

View File

@ -7,51 +7,49 @@ using isn.abst;
namespace isnd.Controllers
{
public partial class PackagesController
{
// Web get the paquet
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Nuget + "/{id}/{lower}/{idf}-{lowerf}."
+ Constants.PaquetFileEstension)]
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Content + "/{id}/{lower}/{idf}-{lowerf}."
+ Constants.PaquetFileEstension)]
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.ContentBase + "/{id}/{version}/{idf}.{versionFromName}."
+ Constants.PacketFileExtension)]
public IActionResult GetPackage(
[FromRoute][SafeName][Required] string id,
[FromRoute][SafeName][Required] string lower,
[FromRoute] string idf, [FromRoute] string lowerf)
[FromRoute][SafeName][Required] string version,
[FromRoute] string idf, [FromRoute] string versionFromName)
{
var pkgpath = Path.Combine(isndSettings.PackagesRootDir,
id, lower, $"{id}-{lower}." + Constants.PaquetFileEstension
var pkgPath = Path.Combine(isndSettings.PackagesRootDir,
id, version, $"{id}-{version}." + Constants.PacketFileExtension
);
FileInfo pkgfi = new FileInfo(pkgpath);
FileInfo pkgFileInfo = new FileInfo(pkgPath);
if (!pkgfi.Exists)
if (!pkgFileInfo.Exists)
{
return BadRequest("!pkgfi.Exists");
return BadRequest("Package does´nt exist in the file system.");
}
return File(pkgfi.OpenRead(), "application/zip; charset=binary");
return File(pkgFileInfo.OpenRead(), "application/zip; charset=binary");
}
// Web get spec
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Nuspec + "/{id}/{lower}/{idf}-{lowerf}."
+ Constants.SpecFileEstension)]
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.ContentBase + "/{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 lowerf)
[FromRoute][SafeName][Required] string lowerFromName)
{
var pkgpath = Path.Combine(isndSettings.PackagesRootDir,
id, lower, $"{id}." + Constants.SpecFileEstension);
var pkgPath = Path.Combine(isndSettings.PackagesRootDir,
id, lower, $"{id}." + Constants.SpecFileExtension);
FileInfo pkgfi = new FileInfo(pkgpath);
if (!pkgfi.Exists)
FileInfo pkgFileInfo = new FileInfo(pkgPath);
if (!pkgFileInfo.Exists)
{
return BadRequest("!pkgfi.Exists");
return BadRequest("Package info does´nt exist in the file system.");
}
return File(pkgfi.OpenRead(), "text/xml; charset=utf-8");
return File(pkgFileInfo.OpenRead(), "text/xml; charset=utf-8");
}
}
}

View File

@ -7,23 +7,31 @@ namespace isnd.Controllers
{
public partial class PackagesController
{
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Find)]
[HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.ContentBase + "/{id}/{version}.json")]
public IActionResult GetVersions(
string id,
string lower,
string version,
bool prerelease = false,
string packageType = null,
int skip = 0,
int take = 25)
int take = 50)
{
NuGetVersion parsedVersion=null;
if (take > maxTake)
{
ModelState.AddModelError("take", "Maximum exceeded");
}
// NugetVersion
if (!NuGetVersion.TryParse(lower, out NuGetVersion parsedVersion))
if ("index"==version)
{
ModelState.AddModelError("lower", "invalid version string");
version=null;
}
if (version!=null)
{
if (!NuGetVersion.TryParse(version, out parsedVersion))
{
ModelState.AddModelError("version", "invalid version string");
}
}
if (!ModelState.IsValid)
{

View File

@ -1,25 +1,13 @@
using Microsoft.VisualBasic.CompilerServices;
using System.Linq.Expressions;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using NuGet.Packaging.Core;
using NuGet.Versioning;
using isnd.Data;
using isnd.Helpers;
using isnd.Entities;
using Microsoft.AspNetCore.Http;
using isn.abst;
using isnd.Data.Packages;
using Microsoft.EntityFrameworkCore;
namespace isnd.Controllers
{
@ -38,184 +26,26 @@ namespace isnd.Controllers
var files = new List<string>();
ViewData["files"] = files;
var clearkey = protector.Unprotect(apiKey);
var apikey = dbContext.ApiKeys.SingleOrDefault(k => k.Id == clearkey);
if (apikey == null)
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();
}
Commit commit = new Commit
{
Action = PackageAction.PublishPackage,
TimeStamp = DateTimeOffset.Now.ToUniversalTime()
};
foreach (IFormFile file in Request.Form.Files)
{
string initpath = Path.Combine(Environment.GetEnvironmentVariable("TEMP") ??
Environment.GetEnvironmentVariable("TMP") ?? "/tmp",
$"isn-{Guid.NewGuid()}."+Constants.PaquetFileEstension);
using (FileStream fw = new FileStream(initpath, FileMode.Create))
{
file.CopyTo(fw);
}
using (FileStream fw = new FileStream(initpath, FileMode.Open))
{
var archive = new ZipArchive(fw);
var spec = archive.Entries.FirstOrDefault(e => e.FullName.EndsWith("." + Constants.SpecFileEstension));
if (spec == null) return BadRequest(new { error = "no " + Constants.SpecFileEstension + " from archive" });
string pkgpath;
NuGetVersion version;
string pkgid;
string fullpath;
using (var specstr = spec.Open())
{
NuspecCoreReader reader = new NuspecCoreReader(specstr);
string pkgdesc = reader.GetDescription();
var types = reader.GetPackageTypes();
pkgid = reader.GetId();
version = reader.GetVersion();
string pkgidpath = Path.Combine(isndSettings.PackagesRootDir,
pkgid);
pkgpath = Path.Combine(pkgidpath, version.ToFullString());
string name = $"{pkgid}-{version}."+Constants.PaquetFileEstension;
fullpath = Path.Combine(pkgpath, name);
var destpkgiddir = new DirectoryInfo(pkgidpath);
Package pkg = dbContext.Packages.SingleOrDefault(p => p.Id == pkgid);
if (pkg != null)
{
if (pkg.OwnerId != apikey.UserId)
{
return new ForbidResult();
}
pkg.Description = pkgdesc;
}
else
{
pkg = new Package
{
Id = pkgid,
Description = pkgdesc,
OwnerId = apikey.UserId,
LatestCommit = commit
};
dbContext.Packages.Add(pkg);
}
if (!destpkgiddir.Exists) destpkgiddir.Create();
var source = new FileInfo(initpath);
var dest = new FileInfo(fullpath);
var destdir = new DirectoryInfo(dest.DirectoryName);
if (dest.Exists)
{
logger.LogWarning($"Existant package on disk : '{dest.FullName}'");
// La version existe sur le disque,
// mais si elle ne l'est pas en base de donnéés,
// on remplace la version sur disque.
string exFullString = version.ToFullString();
var pkgv = dbContext.PackageVersions.
Include(v=>v.LatestCommit)
.SingleOrDefault(
v => v.PackageId == pkg.Id && v.FullString == exFullString
);
if (pkgv!=null && ! pkgv.IsDeleted)
{
string msg = $"existant : {pkg.Id}-{exFullString}";
logger.LogWarning("400 : {msg}", msg);
ModelState.AddModelError("pkgversion", msg);
return BadRequest(this.CreateAPIKO("existant"));
} else dest.Delete();
}
{
if (!destdir.Exists) destdir.Create();
source.MoveTo(fullpath);
files.Add(name);
string fullstringversion = version.ToFullString();
var pkgvers = dbContext.PackageVersions.Where
(v => v.PackageId == pkg.Id && v.FullString == fullstringversion);
if (pkgvers.Count() > 0)
{
foreach (var v in pkgvers.ToArray())
dbContext.PackageVersions.Remove(v);
}
// FIXME default type or null
if (types==null || types.Count==0)
dbContext.PackageVersions.Add
(new PackageVersion{
Package = pkg,
Major = version.Major,
Minor = version.Minor,
Patch = version.Patch,
Revision = version.Revision,
IsPrerelease = version.IsPrerelease,
FullString = version.ToFullString(),
Type = null,
LatestCommit = commit
});
else
foreach (var type in types)
{
var pkgver = new PackageVersion
{
Package = pkg,
Major = version.Major,
Minor = version.Minor,
Patch = version.Patch,
IsPrerelease = version.IsPrerelease,
FullString = version.ToFullString(),
Type = type.Name,
LatestCommit = commit
};
dbContext.PackageVersions.Add(pkgver);
}
dbContext.Commits.Add(commit);
await dbContext.SaveChangesAsync();
await packageManager.ÛpdateCatalogForAsync(commit);
logger.LogInformation($"new paquet : {spec.Name}");
}
}
using (var shacrypto = System.Security.Cryptography.SHA512.Create())
{
using (var stream = System.IO.File.OpenRead(fullpath))
{
var hash = shacrypto.ComputeHash(stream);
var shafullname = fullpath + ".sha512";
var hashtext = Convert.ToBase64String(hash);
var hashtextbytes = Encoding.ASCII.GetBytes(hashtext);
using (var shafile = System.IO.File.OpenWrite(shafullname))
{
shafile.Write(hashtextbytes, 0, hashtextbytes.Length);
}
}
}
string nuspecfullpath = Path.Combine(pkgpath, pkgid + "." + Constants.SpecFileEstension);
FileInfo nfpi = new(nuspecfullpath);
if (nfpi.Exists)
nfpi.Delete();
spec.ExtractToFile(nuspecfullpath);
}
var version = await packageManager.PutPackageAsync(file.OpenReadStream(), dbApiKey.UserId);
logger.LogInformation($"new package : {version.PackageId} {version.NugetLink}");
}
return Ok();
}
catch (Exception ex)
{
logger.LogError("PUT exception : " + ex.Message);
var message = $"PUT exception : {ex.Message} ({ex.GetType().Name})";
logger.LogError(message);
logger.LogError("Stack Trace : " + ex.StackTrace);
return new ObjectResult(new { ViewData, ex.Message })
return new ObjectResult(new { ViewData, message })
{ StatusCode = 500 };
}
}

View File

@ -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);
}
}
}

View File

@ -1,12 +1,15 @@
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;
@ -19,11 +22,30 @@ namespace isnd.Controllers
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<Catalog> registrations = new List<Catalog>();
if (pkgs.data!=null)
if (pkgs.data.Length>0)
{
var grouped = pkgs.data.GroupBy(x => x.PackageId);
if (grouped!=null) if (grouped.Count()>0)
{
foreach (var pk in grouped.ToArray())
{
registrations.Add(new Catalog(apiBase, pk.Key, pkgs.GetResults().Single(p=>p.Id == pk.Key).Versions));
}
}
}
return View(new RegistrationPageIndexQueryAndResult
{
Source = packageManager.CatalogBaseUrl+ApiConfig.Index,
Query = model,
Result = pkgs.ToArray()
Result = registrations.ToArray()
});
}
@ -63,28 +85,28 @@ namespace isnd.Controllers
}
var packageVersion = await dbContext.PackageVersions.Include(p => p.Package)
.FirstOrDefaultAsync(m => m.PackageId == pkgid
&& m.FullString == version && m.Type == pkgtype);
.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);
if (!User.IsOwner(packageVersion)) return Challenge();
var pkg = await packageManager.GetPackageDetailsAsync(pkgid, version, pkgtype);
return View(pkg);
}
// POST: PackageVersion/Delete/5
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(string PackageId, string FullString,
string Type)
[ValidateAntiForgeryToken][Authorize]
public async Task<IActionResult> DeleteConfirmed(string pkgid, string version,
string type)
{
PackageVersion packageVersion = await dbContext.PackageVersions
var packageVersion = await dbContext.PackageVersions
.Include(pv => pv.Package)
.FirstOrDefaultAsync(m => m.PackageId == PackageId
&& m.FullString == FullString && m.Type == Type);
if (packageVersion == null) return NotFound();
if (!User.IsOwner(packageVersion)) return Unauthorized();
await packageManager.DeletePackageAsync(PackageId, FullString, Type);
.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));
}
}

View File

@ -8,6 +8,7 @@ using isnd.Data;
using isnd.Entities;
using isnd.Interfaces;
using isn.Abstract;
using isn.abst;
namespace isnd.Controllers
{
@ -16,6 +17,7 @@ namespace isnd.Controllers
{
const int maxTake = 100;
private readonly Resource[] resources;
private readonly string apiBase;
private readonly ILogger<PackagesController> logger;
private readonly IDataProtector protector;
@ -36,6 +38,9 @@ namespace isnd.Controllers
this.dbContext = dbContext;
packageManager = pm;
resources = packageManager.GetResources().ToArray();
this.apiBase = isndSettings.ExternalUrl + Constants.ApiVersionPrefix;
}
}
}

View File

@ -9,6 +9,8 @@ namespace isnd.Data.ApiKeys
[Display(Name = "Key Name")]
public string Name { get; set; }
public string UserId { get; set; }
public int ValidityPeriodInDays { get; set; }
}
}

View File

@ -2,6 +2,8 @@
using Microsoft.EntityFrameworkCore;
using isnd.Data.ApiKeys;
using isnd.Data.Packages;
using Microsoft.VisualStudio.Web.CodeGenerators.Mvc.Templates.BlazorIdentity.Pages;
using Microsoft.DotNet.Scaffolding.Shared.ProjectModel;
namespace isnd.Data
{
@ -24,6 +26,10 @@ namespace isnd.Data
.HasKey( v => new { v.PackageId, v.FullString } );
_ = builder.Entity<PackageVersion>()
.HasOne(v => v.Package).WithMany(p => p.Versions).HasForeignKey(x => x.PackageId);
_ = builder.Entity<PackageDependencyGroup>().HasOne(g=>g.PackageVersion)
.WithMany(v => v.DependencyGroups).HasForeignKey(x => new { x.PackageId, x.PackageVersionFullString } );
}
@ -50,5 +56,8 @@ namespace isnd.Data
/// </summary>
/// <value></value>
public DbSet<Commit> Commits { get; set; }
public DbSet<Dependency> Dependencies { get; set; }
public DbSet<PackageDependencyGroup> PackageDependencyGroups { get; set; }
}
}

View File

@ -5,6 +5,8 @@ namespace isnd.Data
// Add profile data for application users by adding properties to the ApplicationUser class
public class ApplicationUser : IdentityUser
{
[PersonalData]
public string FullName { get; set; }
}
}

View File

@ -1,6 +0,0 @@
namespace isnd.Data.Catalog
{
public class DependencyGroup
{
}
}

View File

@ -12,33 +12,42 @@ 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
public class PackageDetails : Permalink, IObject
{
/// <summary>
/// Creates a catalog entry
/// </summary>
/// <param name="pkg">package id</param>
/// <param name="apiBase">api Base</param>
/// <param name="uri">package permalink</param>
/// <returns></returns>
public PackageDetails(PackageVersion pkg, string apiBase, string uri): base(uri)
public PackageDetails(PackageVersion pkg, string apiBase): base( apiBase + ApiConfig.Package + "/" + pkg.PackageId + "/" + pkg.FullString)
{
PackageId = pkg.Package.Id;
Title = PackageId = pkg.Package.Id;
Version = pkg.FullString;
Authors = $"{pkg.Package.Owner.FullName} <${pkg.Package.Owner.Email}>";
packageContent = apiBase + pkg.NugetLink;
CommitId = pkg.CommitId;
CommitTimeStamp = pkg.LatestCommit.CommitTimeStamp;
IsListed = !pkg.IsDeleted && pkg.Package.Public;
// TODO Licence Project Urls, Summary, Title, etc ...
Published = CommitTimeStamp = pkg.LatestCommit.CommitTimeStamp;
Listed = !pkg.IsDeleted && pkg.Package.Public;
if (pkg.DependencyGroups!=null)
{
DependencySets = pkg.DependencyGroups;
}
Description = pkg.Description;
Owners = pkg.Package.Owner.Email;
// TODO Licence Project Urls, Summary, Title, Owners, etc ...
}
[JsonProperty("@type")]
public string[] RefType { get; protected set; } = new string[] { "PackageDetails" };
[JsonProperty("commitId")]
public string CommitId { get; set; }
@ -52,12 +61,6 @@ namespace isnd.Data.Catalog
[JsonProperty("authors")]
public string Authors { get; set; }
/// <summary>
/// The dependencies of the package, grouped by target framework
/// </summary>
/// <value>array of objects</value>
public DependencyGroup[] dependencyGroups { get; set; } = Array.Empty<DependencyGroup>();
/// <summary>
/// The deprecation associated with the package
/// </summary>
@ -127,28 +130,23 @@ namespace isnd.Data.Catalog
[JsonProperty("id")]
public string PackageId { get; set; }
public IEnumerable<PackageDependencyGroup> DependencySets { get; set; }
= Array.Empty<PackageDependencyGroup>();
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 bool Listed { get; set; }
public LicenseMetadata LicenseMetadata { get; set; }
[JsonProperty("dependencyGroups")]
public IEnumerable<PackageDependencyGroup> DependencySets {get; set;}
public Task<PackageDeprecationMetadata> GetDeprecationMetadataAsync()
{
throw new NotImplementedException();
@ -159,4 +157,5 @@ namespace isnd.Data.Catalog
throw new NotImplementedException();
}
}
}

View File

@ -1,4 +1,5 @@
using isnd.Data.Packages;
using isnd.Entities;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
@ -6,19 +7,19 @@ using System.Linq;
namespace isnd.Data.Catalog
{
public class PackageRegistration : Permalink
public class Catalog : Permalink
{
public PackageRegistration(string url) : base(url)
public Catalog(string url) : base(url)
{
Items = new List<CatalogPage>();
Items = new List<RegistrationPage>();
}
public PackageRegistration(string bid, string apiBase, Packages.Package pkg) : base(bid + $"/{pkg.Id}/index.json")
public Catalog(string apiBase, string pkgId, IEnumerable<PackageVersion> versions) : base($"{apiBase}{ApiConfig.Registration}/{pkgId}/index.json")
{
Items = new List<CatalogPage>
Items = new List<RegistrationPage>
{
new CatalogPage(bid, pkg.Id, apiBase, pkg.Versions)
new RegistrationPage(pkgId, apiBase, versions)
};
}
@ -26,7 +27,7 @@ namespace isnd.Data.Catalog
public int Count { get => Items.Count; }
[JsonProperty("items")]
public List<CatalogPage> Items { get; set; }
public List<RegistrationPage> Items { get; set; }
}
}

View File

@ -9,15 +9,15 @@ namespace isnd.Data.Catalog
/// Hosts a catalog entry,
/// the atomic content reference
/// </summary>
public class Package
public class RegistrationLeaf
{
public Package(string apiBase, string pkgId, string fullVersionString, PackageDetails entry)
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.PaquetFileEstension;
this.PackageContent = apiBase + ApiConfig.ContentBase + "/" + pkgId + "/" + fullVersionString
+ "/" + pkgId + "-" + fullVersionString + "." + Constants.PacketFileExtension;
Entry = entry;
}

View File

@ -7,23 +7,23 @@ using NuGet.Versioning;
namespace isnd.Data.Catalog
{
public class CatalogPage : Permalink
public class RegistrationPage : Permalink
{
private readonly string pkgid;
private readonly List<Package> items;
private readonly List<RegistrationLeaf> items;
private readonly string apiBase;
public CatalogPage (string pkgid, string apiBase) : base(apiBase + $"/registration/{pkgid}/index.json")
public RegistrationPage (string pkgid, string apiBase) : base(apiBase + $"/registration/{pkgid}/index.json")
{
Parent = apiBase + $"/registration/{pkgid}/index.json";
this.items = new List<Package>();
this.items = new List<RegistrationLeaf>();
this.pkgid = pkgid;
this.apiBase = apiBase;
}
public CatalogPage(string bid, string pkgid, string apiBase, List<PackageVersion> versions) : this(pkgid, apiBase)
public RegistrationPage(string pkgid, string apiBase, IEnumerable<PackageVersion> versions) : this(pkgid, apiBase)
{
AddVersionRange(versions);
}
@ -39,7 +39,7 @@ namespace isnd.Data.Catalog
/// <value></value>
[JsonProperty("items")]
public Package[] Items { get => items.ToArray(); }
public RegistrationLeaf[] Items { get => items.ToArray(); }
public void AddVersionRange(IEnumerable<PackageVersion> vitems)
{
@ -54,6 +54,7 @@ namespace isnd.Data.Catalog
long commitMax = 0;
foreach (var p in vitems)
{
if (p.LatestCommit==null) continue;
var pkg = p.ToPackage(apiBase);
if (items.Contains(pkg)) continue;
@ -69,8 +70,8 @@ namespace isnd.Data.Catalog
}
items.Add(pkg);
}
Upper = upper.ToFullString();
Lower = lower.ToFullString();
Upper = upper?.ToFullString() ?? lower?.ToFullString();
Lower = lower?.ToFullString() ?? upper?.ToFullString();
}
/// <summary>

View File

@ -0,0 +1,42 @@
using System.ComponentModel.DataAnnotations;
using Newtonsoft.Json;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using System.ComponentModel.DataAnnotations.Schema;
using isnd.Data.Packages;
namespace isnd.Data
{
public class Dependency
{
[JsonIgnore]
[Key][DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get;set;}
/// <summary>
/// Dependency Package Identifier
/// </summary>
/// <value></value>
[JsonProperty("id")]
public string PackageId { get;set;}
/// <summary>
/// Dependency Group Id
/// </summary>
/// <value></value>
[Required]
[ForeignKey("Group")]
[JsonIgnore]
public string DependencyGroupId { set ; get ; }
[JsonIgnore]
public virtual PackageDependencyGroup Group{ get; set; }
// TODO Version Range
[JsonProperty("range")][StringLength(1024)]
public string Version { get; set; }
[JsonProperty("exclude")][StringLength(2048)]
public string Exclude { get; set; }
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
namespace isnd.Data.Packages
{
public interface IPackage
{
string Id { get; set; }
string OwnerId { get; set; }
string Description { get; set; }
bool Public { get; set; }
ApplicationUser Owner { get; set; }
List<PackageVersion> Versions { get; set; }
long CommitNId { get; set; }
string CommitId { get; }
Commit LatestCommit { get; set; }
DateTimeOffset CommitTimeStamp { get; set; }
}
}

View File

@ -2,24 +2,13 @@ using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using isnd.Interfaces;
using Newtonsoft.Json;
using NuGet.Versioning;
namespace isnd.Data.Packages
{
public interface IPackage
{
string Id { get; set; }
string OwnerId { get; set; }
string Description { get; set; }
bool Public { get; set; }
ApplicationUser Owner { get; set; }
List<PackageVersion> Versions { get; set; }
long CommitNId { get; set; }
string CommitId { get; }
Commit LatestCommit { get; set; }
DateTimeOffset CommitTimeStamp { get; set; }
}
public class Package
{
@ -60,6 +49,10 @@ namespace isnd.Data.Packages
public virtual Commit LatestCommit { get; set; }
public PackageVersion GetLatestVersion()
{
var latest = Versions.Max(v => v.NugetVersion);
return Versions.FirstOrDefault(v=> v.NugetVersion == latest);
}
}
}

View File

@ -0,0 +1,44 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using isnd.Data.Catalog;
using Microsoft.DotNet.Scaffolding.Shared.ProjectModel;
using Microsoft.Identity.Client;
using Newtonsoft.Json;
using NuGet.Frameworks;
using NuGet.Packaging;
using NuGet.Packaging.Core;
using NuGet.ProjectModel;
using NuGet.Versioning;
namespace isnd.Data
{
public class PackageDependencyGroup
{
[JsonIgnore]
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get ; set;}
[Required]
[JsonIgnore]
public string PackageId { get ; set;}
[Required]
[JsonIgnore]
public string PackageVersionFullString { get ; set;}
[JsonProperty("targetFramework")]
[Required]
public string TargetFramework { get; set; }
[JsonProperty("dependencies")]
[ForeignKey("DependencyGroupId")]
public virtual List<Dependency> Dependencies { get; set; }
[JsonIgnore]
public virtual PackageVersion PackageVersion { get; set; }
}
}

View File

@ -10,6 +10,11 @@ using isnd.Entities;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using NuGet.Versioning;
using System;
using NuGet.Packaging;
using System.Collections.Generic;
using Package = isnd.Data.Packages.Package;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
namespace isnd.Data
{
@ -59,19 +64,27 @@ namespace isnd.Data
public string CommitId { get => CommitNId.ToString(); }
public virtual Commit LatestCommit { get; set; }
public string NugetLink => $"{ApiConfig.Nuget}/{PackageId}/{FullString}/{PackageId}-{FullString}."
+ Constants.PaquetFileEstension;
public string NuspecLink => $"{ApiConfig.Nuspec}/{PackageId}/{FullString}/{PackageId}-{FullString}."
+ Constants.SpecFileEstension;
public virtual List<PackageDependencyGroup> DependencyGroups { get; set; }
public string NugetLink => $"{ApiConfig.ContentBase}/{PackageId}/{FullString}/{PackageId}-{FullString}."
+ Constants.PacketFileExtension;
public string NuspecLink => $"{ApiConfig.ContentBase}/{PackageId}/{FullString}/{PackageId}-{FullString}."
+ Constants.SpecFileExtension;
public string SementicVersionString { get => $"{Major}.{Minor}.{Patch}"; }
public NuGetVersion NugetVersion { get => new NuGetVersion(FullString); }
public Catalog.Package ToPackage(string apiBase)
public Catalog.RegistrationLeaf ToPackage(string apiBase)
{
return new Catalog.Package(apiBase, this.PackageId , FullString,
new Catalog.PackageDetails(this, apiBase, apiBase + ApiConfig.Registration + "/" + this.PackageId + "/" + FullString + ".json"));
return new Catalog.RegistrationLeaf(apiBase, this.PackageId , FullString, new Catalog.PackageDetails(this, apiBase));
}
public bool IsDeleted => LatestCommit.Action == PackageAction.DeletePackage;
public bool IsDeleted => LatestCommit?.Action == PackageAction.DeletePackage;
[StringLength(1024)]
public string Authors { get; set; }
[StringLength(1024)]
public string Description { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using System.Linq;
using System.Threading.Tasks;
using isnd.Data.ApiKeys;
namespace isnd.Interfaces
{
public interface IApiKeyProvider
{
Task<ApiKey> CreateApiKeyAsync(CreateModel model);
IQueryable<ApiKey> GetUserKeys(string identityName);
}
}

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using isn.Abstract;
using isnd.Data;
@ -13,21 +14,23 @@ namespace isnd.Interfaces
public interface IPackageManager
{
string CatalogBaseUrl { get; }
AutoCompleteResult AutoComplete(string pkgid, int skip, int take, bool prerelease = false, string packageType = null);
AutoCompleteResult AutoComplete(string pkgid, int skip=0, int take=25, bool prerelease = false, string packageType = null);
string[] GetVersions(string pkgid, NuGetVersion parsedVersion, bool prerelease = false, string packageType = null, int skip = 0, int take = 25);
IEnumerable<Resource> GetResources();
Task<PackageRegistration> ÛpdateCatalogForAsync(Commit commit);
Task<Catalog> UpdateCatalogForAsync(Commit commit);
Task<PackageDeletionReport> DeletePackageAsync(string pkgid, string version, string type);
Task<PackageDeletionReport> UserAskForPackageDeletionAsync(string userid, string pkgId, string lower, string type);
Task<PackageVersion> GetPackageAsync(string pkgid, string version, string type);
Task<Data.Catalog.Package> GetCatalogEntryAsync(string pkgId, string version, string pkgType);
IEnumerable<Data.Catalog.Package> SearchCatalogEntriesById(string pkgId, string semver, string pkgType, bool preRelease);
Task<PackageDetails> GetPackageDetailsAsync(string pkgid, string version, string type=null);
Task<Data.Catalog.RegistrationLeaf> GetCatalogEntryAsync(string pkgId, string version, string pkgType);
IEnumerable<Data.Catalog.RegistrationLeaf> SearchCatalogEntriesById(string pkgId, string semver, string pkgType, bool preRelease);
Task<PackageRegistration> GetCatalogIndexAsync();
Task<PackageRegistration> GetPackageRegistrationIndexAsync(PackageRegistrationQuery query);
Task<Catalog> GetCatalogIndexAsync();
Task<Catalog> GetPackageRegistrationIndexAsync(PackageRegistrationQuery query);
Task<IEnumerable<PackageRegistration>> SearchPackageAsync(PackageRegistrationQuery query);
Task<PackageSearchResult> SearchPackageAsync(PackageRegistrationQuery query);
Task<PackageVersion> PutPackageAsync(Stream packageStream, string ownerId);
}
}

View File

@ -0,0 +1,529 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using isnd.Data;
#nullable disable
namespace isnd.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20240318003218_dependencies")]
partial class dependencies
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.3")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("ProviderKey")
.HasColumnType("text");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("RoleId")
.HasColumnType("text");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("isnd.Data.ApiKeys.ApiKey", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<DateTimeOffset>("CreationDate")
.HasColumnType("timestamp with time zone");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.Property<int>("ValidityPeriodInDays")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("ApiKeys");
});
modelBuilder.Entity("isnd.Data.ApplicationUser", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<string>("FullName")
.HasColumnType("text");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasColumnType("text");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("isnd.Data.Dependency", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<string>("DependencyGroupId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Exclude")
.HasColumnType("text");
b.Property<string>("Version")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("DependencyGroupId");
b.ToTable("Depedencies");
});
modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<string>("PackageVersionFullString")
.HasColumnType("character varying(256)");
b.Property<string>("PackageVersionId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("PackageVersionPackageId")
.HasColumnType("character varying(1024)");
b.Property<string>("TargetFramework")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("PackageVersionPackageId", "PackageVersionFullString");
b.ToTable("PackageDependencyGroups");
});
modelBuilder.Entity("isnd.Data.PackageVersion", b =>
{
b.Property<string>("PackageId")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<string>("FullString")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<long>("CommitNId")
.HasColumnType("bigint");
b.Property<bool>("IsPrerelease")
.HasColumnType("boolean");
b.Property<int>("Major")
.HasColumnType("integer");
b.Property<int>("Minor")
.HasColumnType("integer");
b.Property<int>("Patch")
.HasColumnType("integer");
b.Property<int>("Revision")
.HasColumnType("integer");
b.Property<string>("Type")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("PackageId", "FullString");
b.HasIndex("CommitNId");
b.ToTable("PackageVersions");
});
modelBuilder.Entity("isnd.Data.Packages.Commit", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<int>("Action")
.HasColumnType("integer");
b.Property<DateTimeOffset>("TimeStamp")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.ToTable("Commits");
});
modelBuilder.Entity("isnd.Data.Packages.Package", b =>
{
b.Property<string>("Id")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<long>("CommitNId")
.HasColumnType("bigint");
b.Property<string>("Description")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<string>("OwnerId")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("Public")
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("CommitNId");
b.HasIndex("OwnerId");
b.ToTable("Packages");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("isnd.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("isnd.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("isnd.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("isnd.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("isnd.Data.ApiKeys.ApiKey", b =>
{
b.HasOne("isnd.Data.ApplicationUser", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("isnd.Data.Dependency", b =>
{
b.HasOne("isnd.Data.PackageDependencyGroup", "Group")
.WithMany("Dependencies")
.HasForeignKey("DependencyGroupId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Group");
});
modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b =>
{
b.HasOne("isnd.Data.PackageVersion", null)
.WithMany("DependencyGroups")
.HasForeignKey("PackageVersionPackageId", "PackageVersionFullString");
});
modelBuilder.Entity("isnd.Data.PackageVersion", b =>
{
b.HasOne("isnd.Data.Packages.Commit", "LatestCommit")
.WithMany("Versions")
.HasForeignKey("CommitNId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("isnd.Data.Packages.Package", "Package")
.WithMany("Versions")
.HasForeignKey("PackageId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("LatestCommit");
b.Navigation("Package");
});
modelBuilder.Entity("isnd.Data.Packages.Package", b =>
{
b.HasOne("isnd.Data.Packages.Commit", "LatestCommit")
.WithMany()
.HasForeignKey("CommitNId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("isnd.Data.ApplicationUser", "Owner")
.WithMany()
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("LatestCommit");
b.Navigation("Owner");
});
modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b =>
{
b.Navigation("Dependencies");
});
modelBuilder.Entity("isnd.Data.PackageVersion", b =>
{
b.Navigation("DependencyGroups");
});
modelBuilder.Entity("isnd.Data.Packages.Commit", b =>
{
b.Navigation("Versions");
});
modelBuilder.Entity("isnd.Data.Packages.Package", b =>
{
b.Navigation("Versions");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,74 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace isnd.Migrations
{
/// <inheritdoc />
public partial class dependencies : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "PackageDependencyGroups",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
PackageVersionId = table.Column<string>(type: "text", nullable: false),
TargetFramework = table.Column<string>(type: "text", nullable: true),
PackageVersionFullString = table.Column<string>(type: "character varying(256)", nullable: true),
PackageVersionPackageId = table.Column<string>(type: "character varying(1024)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PackageDependencyGroups", x => x.Id);
table.ForeignKey(
name: "FK_PackageDependencyGroups_PackageVersions_PackageVersionPacka~",
columns: x => new { x.PackageVersionPackageId, x.PackageVersionFullString },
principalTable: "PackageVersions",
principalColumns: new[] { "PackageId", "FullString" });
});
migrationBuilder.CreateTable(
name: "Depedencies",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
DependencyGroupId = table.Column<string>(type: "text", nullable: false),
Version = table.Column<string>(type: "text", nullable: true),
Exclude = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Depedencies", x => x.Id);
table.ForeignKey(
name: "FK_Depedencies_PackageDependencyGroups_DependencyGroupId",
column: x => x.DependencyGroupId,
principalTable: "PackageDependencyGroups",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Depedencies_DependencyGroupId",
table: "Depedencies",
column: "DependencyGroupId");
migrationBuilder.CreateIndex(
name: "IX_PackageDependencyGroups_PackageVersionPackageId_PackageVers~",
table: "PackageDependencyGroups",
columns: new[] { "PackageVersionPackageId", "PackageVersionFullString" });
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Depedencies");
migrationBuilder.DropTable(
name: "PackageDependencyGroups");
}
}
}

View File

@ -0,0 +1,531 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using isnd.Data;
#nullable disable
namespace isnd.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20240331152055_frameworks")]
partial class frameworks
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.3")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("ProviderKey")
.HasColumnType("text");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("RoleId")
.HasColumnType("text");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("isnd.Data.ApiKeys.ApiKey", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<DateTimeOffset>("CreationDate")
.HasColumnType("timestamp with time zone");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.Property<int>("ValidityPeriodInDays")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("ApiKeys");
});
modelBuilder.Entity("isnd.Data.ApplicationUser", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<string>("FullName")
.HasColumnType("text");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasColumnType("text");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("isnd.Data.Dependency", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<string>("DependencyGroupId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Exclude")
.HasColumnType("text");
b.Property<string>("Version")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("DependencyGroupId");
b.ToTable("Dependencies");
});
modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<string>("PackageId")
.IsRequired()
.HasColumnType("character varying(1024)");
b.Property<string>("PackageVersionFullString")
.IsRequired()
.HasColumnType("character varying(256)");
b.Property<string>("TargetFramework")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("PackageId", "PackageVersionFullString");
b.ToTable("PackageDependencyGroups");
});
modelBuilder.Entity("isnd.Data.PackageVersion", b =>
{
b.Property<string>("PackageId")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<string>("FullString")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<long>("CommitNId")
.HasColumnType("bigint");
b.Property<bool>("IsPrerelease")
.HasColumnType("boolean");
b.Property<int>("Major")
.HasColumnType("integer");
b.Property<int>("Minor")
.HasColumnType("integer");
b.Property<int>("Patch")
.HasColumnType("integer");
b.Property<int>("Revision")
.HasColumnType("integer");
b.Property<string>("Type")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("PackageId", "FullString");
b.HasIndex("CommitNId");
b.ToTable("PackageVersions");
});
modelBuilder.Entity("isnd.Data.Packages.Commit", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<int>("Action")
.HasColumnType("integer");
b.Property<DateTimeOffset>("TimeStamp")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.ToTable("Commits");
});
modelBuilder.Entity("isnd.Data.Packages.Package", b =>
{
b.Property<string>("Id")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<long>("CommitNId")
.HasColumnType("bigint");
b.Property<string>("Description")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<string>("OwnerId")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("Public")
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("CommitNId");
b.HasIndex("OwnerId");
b.ToTable("Packages");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("isnd.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("isnd.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("isnd.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("isnd.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("isnd.Data.ApiKeys.ApiKey", b =>
{
b.HasOne("isnd.Data.ApplicationUser", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("isnd.Data.Dependency", b =>
{
b.HasOne("isnd.Data.PackageDependencyGroup", "Group")
.WithMany("Dependencies")
.HasForeignKey("DependencyGroupId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Group");
});
modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b =>
{
b.HasOne("isnd.Data.PackageVersion", "PackageVersion")
.WithMany("DependencyGroups")
.HasForeignKey("PackageId", "PackageVersionFullString")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("PackageVersion");
});
modelBuilder.Entity("isnd.Data.PackageVersion", b =>
{
b.HasOne("isnd.Data.Packages.Commit", "LatestCommit")
.WithMany("Versions")
.HasForeignKey("CommitNId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("isnd.Data.Packages.Package", "Package")
.WithMany("Versions")
.HasForeignKey("PackageId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("LatestCommit");
b.Navigation("Package");
});
modelBuilder.Entity("isnd.Data.Packages.Package", b =>
{
b.HasOne("isnd.Data.Packages.Commit", "LatestCommit")
.WithMany()
.HasForeignKey("CommitNId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("isnd.Data.ApplicationUser", "Owner")
.WithMany()
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("LatestCommit");
b.Navigation("Owner");
});
modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b =>
{
b.Navigation("Dependencies");
});
modelBuilder.Entity("isnd.Data.PackageVersion", b =>
{
b.Navigation("DependencyGroups");
});
modelBuilder.Entity("isnd.Data.Packages.Commit", b =>
{
b.Navigation("Versions");
});
modelBuilder.Entity("isnd.Data.Packages.Package", b =>
{
b.Navigation("Versions");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,169 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace isnd.Migrations
{
/// <inheritdoc />
public partial class frameworks : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Depedencies_PackageDependencyGroups_DependencyGroupId",
table: "Depedencies");
migrationBuilder.DropForeignKey(
name: "FK_PackageDependencyGroups_PackageVersions_PackageVersionPacka~",
table: "PackageDependencyGroups");
migrationBuilder.DropIndex(
name: "IX_PackageDependencyGroups_PackageVersionPackageId_PackageVers~",
table: "PackageDependencyGroups");
migrationBuilder.DropPrimaryKey(
name: "PK_Depedencies",
table: "Depedencies");
migrationBuilder.DropColumn(
name: "PackageVersionId",
table: "PackageDependencyGroups");
migrationBuilder.DropColumn(
name: "PackageVersionPackageId",
table: "PackageDependencyGroups");
migrationBuilder.RenameTable(
name: "Depedencies",
newName: "Dependencies");
migrationBuilder.RenameIndex(
name: "IX_Depedencies_DependencyGroupId",
table: "Dependencies",
newName: "IX_Dependencies_DependencyGroupId");
migrationBuilder.AlterColumn<string>(
name: "PackageVersionFullString",
table: "PackageDependencyGroups",
type: "character varying(256)",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "character varying(256)",
oldNullable: true);
migrationBuilder.AddColumn<string>(
name: "PackageId",
table: "PackageDependencyGroups",
type: "character varying(1024)",
nullable: false,
defaultValue: "");
migrationBuilder.AddPrimaryKey(
name: "PK_Dependencies",
table: "Dependencies",
column: "Id");
migrationBuilder.CreateIndex(
name: "IX_PackageDependencyGroups_PackageId_PackageVersionFullString",
table: "PackageDependencyGroups",
columns: new[] { "PackageId", "PackageVersionFullString" });
migrationBuilder.AddForeignKey(
name: "FK_Dependencies_PackageDependencyGroups_DependencyGroupId",
table: "Dependencies",
column: "DependencyGroupId",
principalTable: "PackageDependencyGroups",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_PackageDependencyGroups_PackageVersions_PackageId_PackageVe~",
table: "PackageDependencyGroups",
columns: new[] { "PackageId", "PackageVersionFullString" },
principalTable: "PackageVersions",
principalColumns: new[] { "PackageId", "FullString" },
onDelete: ReferentialAction.Cascade);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Dependencies_PackageDependencyGroups_DependencyGroupId",
table: "Dependencies");
migrationBuilder.DropForeignKey(
name: "FK_PackageDependencyGroups_PackageVersions_PackageId_PackageVe~",
table: "PackageDependencyGroups");
migrationBuilder.DropIndex(
name: "IX_PackageDependencyGroups_PackageId_PackageVersionFullString",
table: "PackageDependencyGroups");
migrationBuilder.DropPrimaryKey(
name: "PK_Dependencies",
table: "Dependencies");
migrationBuilder.DropColumn(
name: "PackageId",
table: "PackageDependencyGroups");
migrationBuilder.RenameTable(
name: "Dependencies",
newName: "Depedencies");
migrationBuilder.RenameIndex(
name: "IX_Dependencies_DependencyGroupId",
table: "Depedencies",
newName: "IX_Depedencies_DependencyGroupId");
migrationBuilder.AlterColumn<string>(
name: "PackageVersionFullString",
table: "PackageDependencyGroups",
type: "character varying(256)",
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(256)");
migrationBuilder.AddColumn<string>(
name: "PackageVersionId",
table: "PackageDependencyGroups",
type: "text",
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "PackageVersionPackageId",
table: "PackageDependencyGroups",
type: "character varying(1024)",
nullable: true);
migrationBuilder.AddPrimaryKey(
name: "PK_Depedencies",
table: "Depedencies",
column: "Id");
migrationBuilder.CreateIndex(
name: "IX_PackageDependencyGroups_PackageVersionPackageId_PackageVers~",
table: "PackageDependencyGroups",
columns: new[] { "PackageVersionPackageId", "PackageVersionFullString" });
migrationBuilder.AddForeignKey(
name: "FK_Depedencies_PackageDependencyGroups_DependencyGroupId",
table: "Depedencies",
column: "DependencyGroupId",
principalTable: "PackageDependencyGroups",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_PackageDependencyGroups_PackageVersions_PackageVersionPacka~",
table: "PackageDependencyGroups",
columns: new[] { "PackageVersionPackageId", "PackageVersionFullString" },
principalTable: "PackageVersions",
principalColumns: new[] { "PackageId", "FullString" });
}
}
}

View File

@ -0,0 +1,532 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using isnd.Data;
#nullable disable
namespace isnd.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20240406181803_frameworkRefRequired")]
partial class frameworkRefRequired
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.3")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("ProviderKey")
.HasColumnType("text");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("RoleId")
.HasColumnType("text");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("isnd.Data.ApiKeys.ApiKey", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<DateTimeOffset>("CreationDate")
.HasColumnType("timestamp with time zone");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.Property<int>("ValidityPeriodInDays")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("ApiKeys");
});
modelBuilder.Entity("isnd.Data.ApplicationUser", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<string>("FullName")
.HasColumnType("text");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasColumnType("text");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("isnd.Data.Dependency", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<string>("DependencyGroupId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Exclude")
.HasColumnType("text");
b.Property<string>("Version")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("DependencyGroupId");
b.ToTable("Dependencies");
});
modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<string>("PackageId")
.IsRequired()
.HasColumnType("character varying(1024)");
b.Property<string>("PackageVersionFullString")
.IsRequired()
.HasColumnType("character varying(256)");
b.Property<string>("TargetFramework")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("PackageId", "PackageVersionFullString");
b.ToTable("PackageDependencyGroups");
});
modelBuilder.Entity("isnd.Data.PackageVersion", b =>
{
b.Property<string>("PackageId")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<string>("FullString")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<long>("CommitNId")
.HasColumnType("bigint");
b.Property<bool>("IsPrerelease")
.HasColumnType("boolean");
b.Property<int>("Major")
.HasColumnType("integer");
b.Property<int>("Minor")
.HasColumnType("integer");
b.Property<int>("Patch")
.HasColumnType("integer");
b.Property<int>("Revision")
.HasColumnType("integer");
b.Property<string>("Type")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("PackageId", "FullString");
b.HasIndex("CommitNId");
b.ToTable("PackageVersions");
});
modelBuilder.Entity("isnd.Data.Packages.Commit", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<int>("Action")
.HasColumnType("integer");
b.Property<DateTimeOffset>("TimeStamp")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.ToTable("Commits");
});
modelBuilder.Entity("isnd.Data.Packages.Package", b =>
{
b.Property<string>("Id")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<long>("CommitNId")
.HasColumnType("bigint");
b.Property<string>("Description")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<string>("OwnerId")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("Public")
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("CommitNId");
b.HasIndex("OwnerId");
b.ToTable("Packages");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("isnd.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("isnd.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("isnd.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("isnd.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("isnd.Data.ApiKeys.ApiKey", b =>
{
b.HasOne("isnd.Data.ApplicationUser", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("isnd.Data.Dependency", b =>
{
b.HasOne("isnd.Data.PackageDependencyGroup", "Group")
.WithMany("Dependencies")
.HasForeignKey("DependencyGroupId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Group");
});
modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b =>
{
b.HasOne("isnd.Data.PackageVersion", "PackageVersion")
.WithMany("DependencyGroups")
.HasForeignKey("PackageId", "PackageVersionFullString")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("PackageVersion");
});
modelBuilder.Entity("isnd.Data.PackageVersion", b =>
{
b.HasOne("isnd.Data.Packages.Commit", "LatestCommit")
.WithMany("Versions")
.HasForeignKey("CommitNId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("isnd.Data.Packages.Package", "Package")
.WithMany("Versions")
.HasForeignKey("PackageId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("LatestCommit");
b.Navigation("Package");
});
modelBuilder.Entity("isnd.Data.Packages.Package", b =>
{
b.HasOne("isnd.Data.Packages.Commit", "LatestCommit")
.WithMany()
.HasForeignKey("CommitNId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("isnd.Data.ApplicationUser", "Owner")
.WithMany()
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("LatestCommit");
b.Navigation("Owner");
});
modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b =>
{
b.Navigation("Dependencies");
});
modelBuilder.Entity("isnd.Data.PackageVersion", b =>
{
b.Navigation("DependencyGroups");
});
modelBuilder.Entity("isnd.Data.Packages.Commit", b =>
{
b.Navigation("Versions");
});
modelBuilder.Entity("isnd.Data.Packages.Package", b =>
{
b.Navigation("Versions");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,36 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace isnd.Migrations
{
/// <inheritdoc />
public partial class frameworkRefRequired : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "TargetFramework",
table: "PackageDependencyGroups",
type: "text",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "TargetFramework",
table: "PackageDependencyGroups",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "text");
}
}
}

View File

@ -0,0 +1,535 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using isnd.Data;
#nullable disable
namespace isnd.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20240422204649_dependenciesReloaded")]
partial class dependenciesReloaded
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.3")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("ProviderKey")
.HasColumnType("text");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("RoleId")
.HasColumnType("text");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("isnd.Data.ApiKeys.ApiKey", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<DateTimeOffset>("CreationDate")
.HasColumnType("timestamp with time zone");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.Property<int>("ValidityPeriodInDays")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("ApiKeys");
});
modelBuilder.Entity("isnd.Data.ApplicationUser", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<string>("FullName")
.HasColumnType("text");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasColumnType("text");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("isnd.Data.Dependency", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<string>("DependencyGroupId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Exclude")
.HasColumnType("text");
b.Property<string>("PackageId")
.HasColumnType("text");
b.Property<string>("Version")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("DependencyGroupId");
b.ToTable("Dependencies");
});
modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<string>("PackageId")
.IsRequired()
.HasColumnType("character varying(1024)");
b.Property<string>("PackageVersionFullString")
.IsRequired()
.HasColumnType("character varying(256)");
b.Property<string>("TargetFramework")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("PackageId", "PackageVersionFullString");
b.ToTable("PackageDependencyGroups");
});
modelBuilder.Entity("isnd.Data.PackageVersion", b =>
{
b.Property<string>("PackageId")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<string>("FullString")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<long>("CommitNId")
.HasColumnType("bigint");
b.Property<bool>("IsPrerelease")
.HasColumnType("boolean");
b.Property<int>("Major")
.HasColumnType("integer");
b.Property<int>("Minor")
.HasColumnType("integer");
b.Property<int>("Patch")
.HasColumnType("integer");
b.Property<int>("Revision")
.HasColumnType("integer");
b.Property<string>("Type")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("PackageId", "FullString");
b.HasIndex("CommitNId");
b.ToTable("PackageVersions");
});
modelBuilder.Entity("isnd.Data.Packages.Commit", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<int>("Action")
.HasColumnType("integer");
b.Property<DateTimeOffset>("TimeStamp")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.ToTable("Commits");
});
modelBuilder.Entity("isnd.Data.Packages.Package", b =>
{
b.Property<string>("Id")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<long>("CommitNId")
.HasColumnType("bigint");
b.Property<string>("Description")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<string>("OwnerId")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("Public")
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("CommitNId");
b.HasIndex("OwnerId");
b.ToTable("Packages");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("isnd.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("isnd.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("isnd.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("isnd.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("isnd.Data.ApiKeys.ApiKey", b =>
{
b.HasOne("isnd.Data.ApplicationUser", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("isnd.Data.Dependency", b =>
{
b.HasOne("isnd.Data.PackageDependencyGroup", "Group")
.WithMany("Dependencies")
.HasForeignKey("DependencyGroupId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Group");
});
modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b =>
{
b.HasOne("isnd.Data.PackageVersion", "PackageVersion")
.WithMany("DependencyGroups")
.HasForeignKey("PackageId", "PackageVersionFullString")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("PackageVersion");
});
modelBuilder.Entity("isnd.Data.PackageVersion", b =>
{
b.HasOne("isnd.Data.Packages.Commit", "LatestCommit")
.WithMany("Versions")
.HasForeignKey("CommitNId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("isnd.Data.Packages.Package", "Package")
.WithMany("Versions")
.HasForeignKey("PackageId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("LatestCommit");
b.Navigation("Package");
});
modelBuilder.Entity("isnd.Data.Packages.Package", b =>
{
b.HasOne("isnd.Data.Packages.Commit", "LatestCommit")
.WithMany()
.HasForeignKey("CommitNId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("isnd.Data.ApplicationUser", "Owner")
.WithMany()
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("LatestCommit");
b.Navigation("Owner");
});
modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b =>
{
b.Navigation("Dependencies");
});
modelBuilder.Entity("isnd.Data.PackageVersion", b =>
{
b.Navigation("DependencyGroups");
});
modelBuilder.Entity("isnd.Data.Packages.Commit", b =>
{
b.Navigation("Versions");
});
modelBuilder.Entity("isnd.Data.Packages.Package", b =>
{
b.Navigation("Versions");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,28 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace isnd.Migrations
{
/// <inheritdoc />
public partial class dependenciesReloaded : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "PackageId",
table: "Dependencies",
type: "text",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "PackageId",
table: "Dependencies");
}
}
}

View File

@ -0,0 +1,545 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using isnd.Data;
#nullable disable
namespace isnd.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20241020181446_Authors")]
partial class Authors
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.10")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("ProviderKey")
.HasColumnType("text");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("RoleId")
.HasColumnType("text");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("isnd.Data.ApiKeys.ApiKey", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<DateTimeOffset>("CreationDate")
.HasColumnType("timestamp with time zone");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.Property<int>("ValidityPeriodInDays")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("ApiKeys");
});
modelBuilder.Entity("isnd.Data.ApplicationUser", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<string>("FullName")
.HasColumnType("text");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasColumnType("text");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("isnd.Data.Dependency", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<string>("DependencyGroupId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Exclude")
.HasMaxLength(2048)
.HasColumnType("character varying(2048)");
b.Property<string>("PackageId")
.HasColumnType("text");
b.Property<string>("Version")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.HasKey("Id");
b.HasIndex("DependencyGroupId");
b.ToTable("Dependencies");
});
modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<string>("PackageId")
.IsRequired()
.HasColumnType("character varying(1024)");
b.Property<string>("PackageVersionFullString")
.IsRequired()
.HasColumnType("character varying(256)");
b.Property<string>("TargetFramework")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("PackageId", "PackageVersionFullString");
b.ToTable("PackageDependencyGroups");
});
modelBuilder.Entity("isnd.Data.PackageVersion", b =>
{
b.Property<string>("PackageId")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<string>("FullString")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("Authors")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<long>("CommitNId")
.HasColumnType("bigint");
b.Property<string>("Description")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<bool>("IsPrerelease")
.HasColumnType("boolean");
b.Property<int>("Major")
.HasColumnType("integer");
b.Property<int>("Minor")
.HasColumnType("integer");
b.Property<int>("Patch")
.HasColumnType("integer");
b.Property<int>("Revision")
.HasColumnType("integer");
b.Property<string>("Type")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("PackageId", "FullString");
b.HasIndex("CommitNId");
b.ToTable("PackageVersions");
});
modelBuilder.Entity("isnd.Data.Packages.Commit", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<int>("Action")
.HasColumnType("integer");
b.Property<DateTimeOffset>("TimeStamp")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.ToTable("Commits");
});
modelBuilder.Entity("isnd.Data.Packages.Package", b =>
{
b.Property<string>("Id")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<long>("CommitNId")
.HasColumnType("bigint");
b.Property<string>("Description")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<string>("OwnerId")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("Public")
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("CommitNId");
b.HasIndex("OwnerId");
b.ToTable("Packages");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("isnd.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("isnd.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("isnd.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("isnd.Data.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("isnd.Data.ApiKeys.ApiKey", b =>
{
b.HasOne("isnd.Data.ApplicationUser", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("isnd.Data.Dependency", b =>
{
b.HasOne("isnd.Data.PackageDependencyGroup", "Group")
.WithMany("Dependencies")
.HasForeignKey("DependencyGroupId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Group");
});
modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b =>
{
b.HasOne("isnd.Data.PackageVersion", "PackageVersion")
.WithMany("DependencyGroups")
.HasForeignKey("PackageId", "PackageVersionFullString")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("PackageVersion");
});
modelBuilder.Entity("isnd.Data.PackageVersion", b =>
{
b.HasOne("isnd.Data.Packages.Commit", "LatestCommit")
.WithMany("Versions")
.HasForeignKey("CommitNId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("isnd.Data.Packages.Package", "Package")
.WithMany("Versions")
.HasForeignKey("PackageId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("LatestCommit");
b.Navigation("Package");
});
modelBuilder.Entity("isnd.Data.Packages.Package", b =>
{
b.HasOne("isnd.Data.Packages.Commit", "LatestCommit")
.WithMany()
.HasForeignKey("CommitNId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("isnd.Data.ApplicationUser", "Owner")
.WithMany()
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("LatestCommit");
b.Navigation("Owner");
});
modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b =>
{
b.Navigation("Dependencies");
});
modelBuilder.Entity("isnd.Data.PackageVersion", b =>
{
b.Navigation("DependencyGroups");
});
modelBuilder.Entity("isnd.Data.Packages.Commit", b =>
{
b.Navigation("Versions");
});
modelBuilder.Entity("isnd.Data.Packages.Package", b =>
{
b.Navigation("Versions");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,80 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace isnd.Migrations
{
/// <inheritdoc />
public partial class Authors : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Authors",
table: "PackageVersions",
type: "character varying(1024)",
maxLength: 1024,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Description",
table: "PackageVersions",
type: "character varying(1024)",
maxLength: 1024,
nullable: true);
migrationBuilder.AlterColumn<string>(
name: "Version",
table: "Dependencies",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Exclude",
table: "Dependencies",
type: "character varying(2048)",
maxLength: 2048,
nullable: true,
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Authors",
table: "PackageVersions");
migrationBuilder.DropColumn(
name: "Description",
table: "PackageVersions");
migrationBuilder.AlterColumn<string>(
name: "Version",
table: "Dependencies",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Exclude",
table: "Dependencies",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048,
oldNullable: true);
}
}
}

View File

@ -17,7 +17,7 @@ namespace isnd.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.4")
.HasAnnotation("ProductVersion", "8.0.10")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
@ -247,6 +247,59 @@ namespace isnd.Migrations
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("isnd.Data.Dependency", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<string>("DependencyGroupId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Exclude")
.HasMaxLength(2048)
.HasColumnType("character varying(2048)");
b.Property<string>("PackageId")
.HasColumnType("text");
b.Property<string>("Version")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.HasKey("Id");
b.HasIndex("DependencyGroupId");
b.ToTable("Dependencies");
});
modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("text");
b.Property<string>("PackageId")
.IsRequired()
.HasColumnType("character varying(1024)");
b.Property<string>("PackageVersionFullString")
.IsRequired()
.HasColumnType("character varying(256)");
b.Property<string>("TargetFramework")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("PackageId", "PackageVersionFullString");
b.ToTable("PackageDependencyGroups");
});
modelBuilder.Entity("isnd.Data.PackageVersion", b =>
{
b.Property<string>("PackageId")
@ -257,9 +310,17 @@ namespace isnd.Migrations
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("Authors")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<long>("CommitNId")
.HasColumnType("bigint");
b.Property<string>("Description")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<bool>("IsPrerelease")
.HasColumnType("boolean");
@ -396,6 +457,28 @@ namespace isnd.Migrations
b.Navigation("User");
});
modelBuilder.Entity("isnd.Data.Dependency", b =>
{
b.HasOne("isnd.Data.PackageDependencyGroup", "Group")
.WithMany("Dependencies")
.HasForeignKey("DependencyGroupId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Group");
});
modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b =>
{
b.HasOne("isnd.Data.PackageVersion", "PackageVersion")
.WithMany("DependencyGroups")
.HasForeignKey("PackageId", "PackageVersionFullString")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("PackageVersion");
});
modelBuilder.Entity("isnd.Data.PackageVersion", b =>
{
b.HasOne("isnd.Data.Packages.Commit", "LatestCommit")
@ -434,6 +517,16 @@ namespace isnd.Migrations
b.Navigation("Owner");
});
modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b =>
{
b.Navigation("Dependencies");
});
modelBuilder.Entity("isnd.Data.PackageVersion", b =>
{
b.Navigation("DependencyGroups");
});
modelBuilder.Entity("isnd.Data.Packages.Commit", b =>
{
b.Navigation("Versions");

View File

@ -0,0 +1,48 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using isnd.Data;
using isnd.Data.ApiKeys;
using isnd.Entities;
using isnd.Interfaces;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
namespace isnd;
public class ApiKeyProvider : IApiKeyProvider
{
private readonly IsndSettings isndSettings;
private readonly IDataProtector protector;
private readonly ApplicationDbContext dbContext;
public ApiKeyProvider(
ApplicationDbContext dbContext,
IDataProtectionProvider dataProtectionProvider, IOptions<IsndSettings> isndSettingsOptions)
{
this.dbContext = dbContext;
isndSettings = isndSettingsOptions.Value;
protector = dataProtectionProvider.CreateProtector(isndSettings.ProtectionTitle);
}
public async Task<ApiKey> CreateApiKeyAsync(CreateModel model)
{
var newKey = new ApiKey{
UserId = model.UserId,
CreationDate = DateTime.Now.ToUniversalTime(),
Name = model.Name,
ValidityPeriodInDays = model.ValidityPeriodInDays
};
_ = dbContext.ApiKeys.Add(newKey);
_ = await dbContext.SaveChangesAsync();
return newKey;
}
public IQueryable<ApiKey> GetUserKeys(string identityName)
{
return dbContext.ApiKeys.Include(k => k.User).Where(k => k.User.UserName == identityName);
}
}

View File

@ -15,13 +15,13 @@ namespace isnd.Services
public class EmailSender : IEmailSender, IMailer
{
public EmailSender(IOptions<SmtpSettings> smtpSettings,
IHostingEnvironment env)
IWebHostEnvironment env)
{
Options = smtpSettings.Value;
Env = env;
}
public SmtpSettings Options { get; } //set only via Secret Manager
public IHostingEnvironment Env { get; }
public IWebHostEnvironment Env { get; }
public Task SendEmailAsync(string email, string subject, string message)
{
return Execute(Options.SenderName, subject, message, email);
@ -32,7 +32,7 @@ namespace isnd.Services
await SendMailAsync(name, email, subject, message);
}
public async Task SendMailAsync(string name, string email, string subjet, string body)
public async Task SendMailAsync(string name, string email, string subject, string body)
{
try {
var message = new MimeMessage();

View File

@ -0,0 +1,11 @@
using System.Collections.Generic;
namespace isnd.Services
{
public class FrameworkDependencyGroup
{
internal string FrameworkName { get; set; }
internal List<ShortDependencyInfo> Dependencies { get; set; }
}
}

View File

@ -0,0 +1,25 @@
using System;
using System.Runtime.Serialization;
namespace isnd.Services
{
[Serializable]
internal class InvalidPackageException : InvalidOperationException
{
public InvalidPackageException()
{
}
public InvalidPackageException(string message) : base(message)
{
}
public InvalidPackageException(string message, Exception innerException) : base(message, innerException)
{
}
protected InvalidPackageException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
}

View File

@ -1,7 +1,12 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using isn.abst;
using isn.Abstract;
using isnd.Data;
@ -10,9 +15,11 @@ using isnd.Data.Packages;
using isnd.Entities;
using isnd.Interfaces;
using isnd.ViewModels;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using NuGet.Versioning;
using System.Xml;
using System.Xml.Linq;
using NuGet.Protocol;
using System.ComponentModel;
namespace isnd.Services
{
@ -31,7 +38,7 @@ namespace isnd.Services
public IEnumerable<Resource> GetResources()
{
var res = new List<Resource>
{
new Resource(apiBase + ApiConfig.Package,
@ -41,13 +48,13 @@ namespace isnd.Services
},
// under dev, only leash in release mode
new Resource(apiBase + ApiConfig.Package + "/{id}/{version}",
new Resource(apiBase + ApiConfig.PackageDetailUriTemplate,
"PackageDetailsUriTemplate/5.1.0")
{
Comment = "URI template used by NuGet Client to construct details URL for packages"
},
new Resource(apiBase + ApiConfig.Content,
new Resource(apiBase + ApiConfig.ContentBase + "/",
"PackageBaseAddress/3.0.0")
{
Comment = "Package Base Address service - " +
@ -62,11 +69,25 @@ namespace isnd.Services
},
new Resource(apiBase + ApiConfig.Search,
"SearchQueryService/" + BASE_API_LEVEL)
"SearchQueryService")
{
Comment = "Search Query service"
Comment = "Query endpoint of NuGet Search service (primary) used by RC clients"
},
new Resource(apiBase + ApiConfig.Search,
"SearchQueryService/3.0.0-beta")
{
Comment = "Query endpoint of NuGet Search service (primary) used by RC clients"
},
new Resource(apiBase + ApiConfig.Search,
"SearchQueryService/3.0.0-rc")
{
Comment = "Query endpoint of NuGet Search service (primary) used by RC clients"
},
new Resource(apiBase + ApiConfig.Search,
"SearchQueryService/3.5.0")
{
Comment = "Query endpoint of NuGet Search service (primary) used by RC clients"
},
new Resource(apiBase + ApiConfig.Registration,
"RegistrationsBaseUrl/Versioned")
@ -75,9 +96,6 @@ namespace isnd.Services
"This base URL includes SemVer 2.0.0 packages."
}
};
// TODO ? RegistrationsBaseUrl RegistrationsBaseUrl/v* Catalog
return res;
}
@ -102,43 +120,73 @@ namespace isnd.Services
public string[] GetVersions(
string id,
NuGetVersion parsedVersion = null,
bool prerelease = false,
bool prerelease = true,
string packageType = null,
int skip = 0,
int take = 25)
{
return dbContext.PackageVersions.Where(
v => v.PackageId == id
&& (prerelease || !v.IsPrerelease)
&& (packageType == null || v.Type == packageType)
&& (parsedVersion==null || parsedVersion.CompareTo
(new SemanticVersion(v.Major, v.Minor, v.Patch)) < 0)
)
.OrderBy(v => v.NugetVersion)
.Select(v => v.FullString)
.Skip(skip).Take(take).ToArray();
if (!String.IsNullOrWhiteSpace(id))
{
id = id.ToLower();
if (!String.IsNullOrWhiteSpace(packageType))
{
packageType = packageType.ToLower();
}
IQueryable<PackageVersion> results =
(parsedVersion != null) ?
(packageType == null) ?
dbContext.PackageVersions.Where(
v => v.PackageId.ToLower() == id
&& (prerelease || !v.IsPrerelease)
&& (parsedVersion.CompareTo(new SemanticVersion(v.Major, v.Minor, v.Patch)) < 0)
)
:
dbContext.PackageVersions.Where(
v => v.PackageId.ToLower() == id
&& (prerelease || !v.IsPrerelease)
&& (v.Type == packageType)
&& (parsedVersion.CompareTo(new SemanticVersion(v.Major, v.Minor, v.Patch)) < 0)
)
:
(packageType == null) ?
dbContext.PackageVersions.Where(
v => v.PackageId.ToLower() == id
&& (prerelease || !v.IsPrerelease)
)
:
dbContext.PackageVersions.Where(
v => v.PackageId.ToLower() == id
&& (prerelease || !v.IsPrerelease)
&& (v.Type == packageType)
)
;
var res = results.Select(v => v.FullString)
.Skip(skip).Take(take).ToArray();
return res;
}
return null;
}
public string CatalogBaseUrl => apiBase;
private IsndSettings isndSettings;
private readonly string apiBase;
public virtual async Task<PackageRegistration> GetCatalogIndexAsync()
public virtual async Task<Catalog> GetCatalogIndexAsync()
{
return await ÛpdateCatalogForAsync(null);
return await UpdateCatalogForAsync(null);
}
public async Task<PackageRegistration> ÛpdateCatalogForAsync
public async Task<Catalog> UpdateCatalogForAsync
(Commit reason = null)
{
int i = 0;
string baseid = apiBase + ApiConfig.Catalog;
string bidreg = $"{apiBase}{ApiConfig.Registration}";
PackageRegistration index = new PackageRegistration(baseid);
string baseId = apiBase + ApiConfig.Catalog;
string baseRegistrationId = $"{apiBase}{ApiConfig.Registration}";
Catalog index = new Catalog(baseId);
var scope = await dbContext.Commits.OrderBy(c => c.TimeStamp).ToArrayAsync();
@ -146,28 +194,26 @@ namespace isnd.Services
i = isndSettings.CatalogPageLen;
foreach (var commit in scope)
{
var validPkgs = (await dbContext.Packages
.Include(po => po.Owner)
.Include(pkg => pkg.Versions)
.Include(pkg => pkg.LatestCommit)
.ToArrayAsync())
.GroupBy((q) => q.Id);
foreach (var pkgid in validPkgs)
foreach (var pkgIdGroup in validPkgs)
{
CatalogPage page = index.Items.FirstOrDefault
(p => p.GetPackageId() == pkgid.Key);
RegistrationPage page = index.Items.FirstOrDefault
(p => p.GetPackageId() == pkgIdGroup.Key);
if (page == null)
{
page = new CatalogPage(pkgid.Key, apiBase);
page = new RegistrationPage(pkgIdGroup.Key, apiBase);
index.Items.Add(page);
}
foreach (var pkgv in pkgid)
foreach (var package in pkgIdGroup)
{
page.AddVersionRange(pkgv.Versions);
page.AddVersionRange(package.Versions);
}
}
reason = commit;
@ -177,7 +223,7 @@ namespace isnd.Services
}
public async Task<PackageDeletionReport> DeletePackageAsync
(string pkgid, string version, string type)
(string pkgId, string version, string type)
{
// TODO deletion on disk
var commit = new Commit
@ -187,7 +233,7 @@ namespace isnd.Services
};
dbContext.Commits.Add(commit);
var pkg = await dbContext.PackageVersions.SingleOrDefaultAsync(
v => v.PackageId == pkgid &&
v => v.PackageId == pkgId &&
v.FullString == version &&
v.Type == type
);
@ -197,28 +243,51 @@ namespace isnd.Services
}
dbContext.PackageVersions.Remove(pkg);
await dbContext.SaveChangesAsync();
await ÛpdateCatalogForAsync(commit);
await UpdateCatalogForAsync(commit);
return new PackageDeletionReport { Deleted = true, DeletedVersion = pkg };
}
public async Task<PackageVersion> GetPackageAsync
(string pkgid, string version, string type)
public async Task<PackageDetails> GetPackageDetailsAsync
(string pkgId, string version, string type)
{
return await dbContext.PackageVersions.SingleOrDefaultAsync(
v => v.PackageId == pkgid &&
var pkg = await dbContext.PackageVersions
.Include(v => v.Package)
.Include(v => v.Package.Owner)
.Include(v => v.LatestCommit)
.Include(v => v.DependencyGroups)
.SingleOrDefaultAsync(
v => v.PackageId == pkgId &&
v.FullString == version &&
v.Type == type
);
(type == null || v.Type == type))
;
if (pkg == null) return null;
foreach (var g in pkg.DependencyGroups)
{
g.Dependencies = dbContext.Dependencies.Where(d => d.DependencyGroupId == g.Id).ToList();
}
return new PackageDetails(pkg, apiBase);
}
public async Task<Data.Catalog.Package> GetCatalogEntryAsync
(string pkgId, string semver = null, string pkgType = null)
public async Task<Data.Catalog.RegistrationLeaf> GetCatalogEntryAsync
(string pkgId, string semver, string pkgType = "Dependency")
{
return (await dbContext.PackageVersions
.Include(v => v.Package).Include(v => v.Package.Owner)
.Where(v => v.PackageId == pkgId
&& v.FullString == semver).SingleOrDefaultAsync()).ToPackage(
apiBase);
var version = await dbContext.PackageVersions
.Include(v => v.Package)
.Include(v => v.Package.LatestCommit)
.Include(v => v.Package.Owner)
.Include(v => v.DependencyGroups)
.Include(v => v.LatestCommit)
.Where(v => v.PackageId == pkgId
&& v.FullString == semver
&& v.LatestCommit != null
&& (pkgType == null || pkgType == v.Type)
).SingleOrDefaultAsync();
if (version == null) return null;
foreach (var g in version.DependencyGroups)
{
g.Dependencies = dbContext.Dependencies.Where(d => d.DependencyGroupId == g.Id).ToList();
}
return version.ToPackage(apiBase);
}
public async Task<PackageDeletionReport> UserAskForPackageDeletionAsync
@ -227,21 +296,23 @@ namespace isnd.Services
PackageVersion packageVersion = await dbContext.PackageVersions
.Include(pv => pv.Package)
.FirstOrDefaultAsync(m => m.PackageId == id
&& m.FullString == lower && m.Type == type);
&& m.FullString == lower && (type == null || m.Type == type));
if (packageVersion == null) return null;
if (packageVersion.Package.OwnerId != uid) return null;
return new PackageDeletionReport { Deleted = true, DeletedVersion = packageVersion };
}
public IEnumerable<Data.Catalog.Package> SearchCatalogEntriesById
public IEnumerable<Data.Catalog.RegistrationLeaf> SearchCatalogEntriesById
(string pkgId, string semver, string pkgType, bool preRelease)
{
// PackageDependency
return dbContext.PackageVersions
.Include(v => v.Package)
.Include(v => v.Package.Owner)
.Include(v => v.Package.LatestCommit)
.Include(v => v.LatestCommit)
.Include(v => v.DependencyGroups)
.Where(v => v.PackageId == pkgId && semver == v.FullString
&& (pkgType == null || pkgType == v.Type)
&& (preRelease || !v.IsPrerelease))
@ -254,52 +325,252 @@ namespace isnd.Services
return dbContext.PackageVersions
.Include(v => v.Package)
.Include(v => v.LatestCommit)
.Include(v => v.DependencyGroups.Last().Dependencies)
.Single(v => v.PackageId == pkgId && semver == v.FullString
&& (pkgType == null || pkgType == v.Type));
}
public async Task<PackageRegistration> GetPackageRegistrationIndexAsync
public async Task<Catalog> GetPackageRegistrationIndexAsync
(PackageRegistrationQuery query)
{
// RegistrationPageIndexAndQuery
if (string.IsNullOrWhiteSpace(query.Query)) return null;
query.Query = query.Query.ToLower();
var scope = await dbContext.Packages
.Include(p => p.Versions)
.Include(p => p.Owner)
var scope = await dbContext.PackageVersions
.Include(p => p.Package)
.Include(p => p.Package.Owner)
.Include(p => p.LatestCommit)
.SingleOrDefaultAsync(p => p.Id.ToLower() == query.Query);
if (scope==null) return null;
if (scope.Versions.Count==0) return null;
.Where(p => p.PackageId.ToLower() == query.Query).ToArrayAsync();
if (scope == null) return null;
if (scope.Length == 0) return null;
string bid = $"{apiBase}{ApiConfig.Registration}";
foreach (var version in scope.Versions)
version.LatestCommit = dbContext.Commits.Single(c=>c.Id == version.CommitNId);
return
new PackageRegistration(bid, apiBase, scope);
foreach (var version in scope)
{
version.DependencyGroups = dbContext.PackageDependencyGroups.Include(d => d.Dependencies)
.Where(d => d.PackageId == version.PackageId && d.PackageVersionFullString == version.FullString)
.ToList();
version.LatestCommit = dbContext.Commits.Single(c => c.Id == version.CommitNId);
}
return new Catalog(apiBase, query.Query, scope);
}
public async Task<IEnumerable<PackageRegistration>> SearchPackageAsync(PackageRegistrationQuery query)
public async Task<PackageSearchResult> SearchPackageAsync(PackageRegistrationQuery query)
{
string bid = $"{apiBase}{ApiConfig.Registration}";
if (string.IsNullOrWhiteSpace(query.Query))
{
query.Query = "";
return new PackageSearchResult(apiBase);
}
if (query.Query == null) query.Query = "";
var scope = (await dbContext.Packages
.Include(p => p.Owner)
.Include(p => p.Versions)
.Include(p => p.LatestCommit)
.Where(p => p.Id.StartsWith(query.Query)
&& (query.Prerelease || p.Versions.Any(p => !p.IsPrerelease)))
.OrderBy(p => p.CommitNId)
.Skip(query.Skip).Take(query.Take)
.ToListAsync()
);
scope.ForEach(pkg =>
pkg.Versions.ForEach (version =>
version.LatestCommit = dbContext.Commits.Single(c => c.Id == version.CommitNId))
);
var allPackages = dbContext.Packages
.Include(g => g.Versions).OrderBy(v => v.CommitNId)
.Where(d => d.Id.StartsWith(query.Query)
&& (query.Prerelease || d.Versions.Any(v => !v.IsPrerelease)))
.Where(p => p.Versions.Count >= 0);
return scope.Select(p => new PackageRegistration(bid, apiBase, p));
var count = await allPackages.CountAsync();
var packages = await allPackages
.Skip(query.Skip).Take(query.Take).ToArrayAsync();
foreach (var package in packages)
foreach (var version in package.Versions)
{
version.DependencyGroups = dbContext.PackageDependencyGroups.Include(d => d.Dependencies)
.Where(d => d.PackageVersionFullString == version.FullString && d.PackageId == version.PackageId)
.ToList();
}
return new PackageSearchResult(packages, apiBase, count);
}
public async Task<PackageVersion> PutPackageAsync(Stream packageStream, string ownerId)
{
PackageVersion version = null;
using (packageStream)
{
using (var archive = new ZipArchive(packageStream))
{
var spec = archive.Entries.FirstOrDefault(e => e.FullName.EndsWith("." + Constants.SpecFileExtension));
if (spec == null) throw new InvalidPackageException("no " + Constants.SpecFileExtension + " from archive");
string pkgPath;
NuGetVersion nugetVersion;
string pkgId;
string fullPath;
using var specificationStream = spec.Open();
using XmlReader xmlReader = XmlReader.Create(specificationStream);
var xMeta = XElement.Load(xmlReader, LoadOptions.None).Descendants().First();
var xMetaElts = xMeta.Descendants();
string description = xMetaElts.FirstOrDefault(x => x.Name.LocalName == "description")?.Value;
var dependencies = xMeta
.Descendants().FirstOrDefault(x => x.Name.LocalName == "dependencies");
var frameworkReferences = xMeta
.Descendants().FirstOrDefault(x => x.Name.LocalName == "frameworkReferences");
var frameWorks = (dependencies ?? frameworkReferences)
.Descendants().Where(x => x.Name.LocalName == "group")
.Select(x => NewFrameworkDependencyGroup(x)).ToArray();
// FIXME default package type or null
var types = "Dependency";
pkgId = xMetaElts.FirstOrDefault(x => x.Name.LocalName == "id")?.Value;
string pkgVersion = xMetaElts.FirstOrDefault(x => x.Name.LocalName == "version")?.Value;
if (!NuGetVersion.TryParse(pkgVersion, out nugetVersion))
throw new InvalidPackageException("metadata/version");
string packageIdPath = Path.Combine(isndSettings.PackagesRootDir,
pkgId);
pkgPath = Path.Combine(packageIdPath, nugetVersion.ToFullString());
string name = $"{pkgId}-{nugetVersion}." + Constants.PacketFileExtension;
fullPath = Path.Combine(pkgPath, name);
var authors = xMetaElts.FirstOrDefault(x => x.Name.LocalName == "authors")?.Value;
var packageIdPathInfo = new DirectoryInfo(packageIdPath);
Data.Packages.Package pkg = dbContext.Packages.SingleOrDefault(p => p.Id == pkgId);
Commit commit = new Commit
{
Action = PackageAction.PublishPackage,
TimeStamp = DateTimeOffset.Now.ToUniversalTime()
};
if (pkg != null)
{
// Update
}
else
{
// First version
pkg = new Package
{
Id = pkgId,
OwnerId = ownerId,
Public = true,
};
dbContext.Packages.Add(pkg);
}
pkg.LatestCommit = commit;
// here, the package is or new, or owned by the key owner
if (!packageIdPathInfo.Exists) packageIdPathInfo.Create();
var dest = new FileInfo(fullPath);
var destDir = new DirectoryInfo(dest.DirectoryName);
if (dest.Exists) dest.Delete();
if (!destDir.Exists) destDir.Create();
packageStream.Seek(0, SeekOrigin.Begin);
using (var fileStream = File.Create(fullPath))
{
await packageStream.CopyToAsync(fileStream);
}
string fullStringVersion = nugetVersion.ToFullString();
var pkgVersions = dbContext.PackageVersions.Where
(v => v.PackageId == pkg.Id && v.FullString == fullStringVersion);
if (pkgVersions.Count() > 0)
{
foreach (var v in pkgVersions.ToArray())
dbContext.PackageVersions.Remove(v);
}
string versionFullString = nugetVersion.ToFullString();
dbContext.PackageVersions.Add
(version = new PackageVersion
{
Package = pkg,
Major = nugetVersion.Major,
Minor = nugetVersion.Minor,
Patch = nugetVersion.Patch,
Revision = nugetVersion.Revision,
IsPrerelease = nugetVersion.IsPrerelease,
FullString = versionFullString,
Type = types,
LatestCommit = commit,
Authors = authors,
Description = description
});
dbContext.Commits.Add(commit);
foreach (var group in dbContext.PackageDependencyGroups.Include(g => g.PackageVersion)
.Where(x => x.PackageId == pkgId && x.PackageVersionFullString == versionFullString)
.ToList())
{
dbContext.PackageDependencyGroups.Remove(group);
}
version.DependencyGroups = new List<PackageDependencyGroup>();
foreach (var framework in frameWorks)
{
var group = new PackageDependencyGroup
{
TargetFramework = framework.FrameworkName,
PackageId = pkgId,
PackageVersionFullString = versionFullString,
Dependencies = framework.Dependencies.Select(
d => new Dependency
{
PackageId = d.PackageId,
Version = d.PackageVersion,
}).ToList()
};
version.DependencyGroups.Add(group);
dbContext.PackageDependencyGroups.Add(group);
}
await dbContext.SaveChangesAsync();
await UpdateCatalogForAsync(commit);
using (var shaCrypto = System.Security.Cryptography.SHA512.Create())
{
using (var stream = System.IO.File.OpenRead(fullPath))
{
var hash = shaCrypto.ComputeHash(stream);
var shaFullName = fullPath + ".sha512";
var hashText = Convert.ToBase64String(hash);
var hashTextBytes = Encoding.ASCII.GetBytes(hashText);
using (var shaFile = System.IO.File.OpenWrite(shaFullName))
{
shaFile.Write(hashTextBytes, 0, hashTextBytes.Length);
}
}
}
string nugetSpecificationFullPath = Path.Combine(pkgPath, pkgId + "." + Constants.SpecFileExtension);
FileInfo nugetSpecificationFullPathInfo = new(nugetSpecificationFullPath);
if (nugetSpecificationFullPathInfo.Exists)
nugetSpecificationFullPathInfo.Delete();
spec.ExtractToFile(nugetSpecificationFullPath);
}
}
return version;
}
private FrameworkDependencyGroup NewFrameworkDependencyGroup(XElement x)
{
var view = x.ToJson();
var frameworkReferences = x.Descendants();
var framework = x.Attribute("targetFramework").Value;
var deps = frameworkReferences.Select(r => new ShortDependencyInfo
{
PackageId = (r.Attribute("name") ?? r.Attribute("id")).Value,
PackageVersion = r.Attribute("version")?.Value
});
return new FrameworkDependencyGroup
{
FrameworkName = framework,
Dependencies = deps.ToList()
};
}
}
}

View File

@ -0,0 +1,8 @@
namespace isnd.Services
{
public class ShortDependencyInfo
{
internal string PackageId { get; set;}
internal string PackageVersion { get; set;}
}
}

View File

@ -16,9 +16,9 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System;
using Microsoft.OpenApi.Models;
using System.IO;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.DataProtection;
namespace isnd
{
@ -60,7 +60,7 @@ namespace isnd
.AddDefaultUI()
.AddDefaultTokenProviders();
services.AddMvc(o => o.EnableEndpointRouting = false);
services.AddMvc(o => o.EnableEndpointRouting = false).AddMvcLocalization();
services.AddDataProtection();
@ -76,9 +76,9 @@ namespace isnd
.AddTransient<IMailer, EmailSender>()
.AddTransient<IEmailSender, EmailSender>()
.AddTransient<IPackageManager, PackageManager>()
.AddTransient<IApiKeyProvider, ApiKeyProvider>()
.AddSingleton<IAuthorizationHandler, ValidApiKeyRequirementHandler>();
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
@ -95,6 +95,7 @@ namespace isnd
s.SerializerSettings.ReferenceResolverProvider = () => new NSJWebApiReferenceResolver();
})
.AddXmlSerializerFormatters();
#if SWAGGER
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
@ -117,6 +118,8 @@ namespace isnd
var xmlFilename = $"{typeof(Startup).Assembly.GetName().Name}.xml";
options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
});
#endif
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@ -130,8 +133,10 @@ namespace isnd
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
#if SWAGGER
app.UseSwagger();
app.UseSwaggerUI();
#endif
}
else
{
@ -139,7 +144,7 @@ namespace isnd
app.UseHsts();
dbContext.Database.Migrate();
}
app.UseStatusCodePages().UseStaticFiles().UseAuthentication();
app.UseStatusCodePagesWithReExecute("/Home/Error/{0}").UseStaticFiles().UseAuthentication();
app.UseMvcWithDefaultRoute();
}
}

View File

@ -5,5 +5,7 @@ namespace isnd.ViewModels
{
public int PkgCount { get; set; }
public string APIUrl { get; set; }
}
}

View File

@ -0,0 +1,72 @@
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using isnd.Data.Catalog;
using Newtonsoft.Json;
using NuGet.Packaging.Core;
using NuGet.Protocol.Core.Types;
namespace isnd.ViewModels
{
public class PackageHit : Permalink
{
public PackageHit(string registrationId, string packageId,
string version, string description
) : base(registrationId, "Package")
{
PackageId = packageId;
registration = registrationId;
this.verified = verified;
this.description = description;
Debug.Assert(version!=null);
}
/// <summary>
/// The full SemVer 2.0.0 version string of the package (could contain build metadata)
/// </summary>
/// <value></value>
[Required]
public string version { get; set; }
/// <summary>
/// All of the versions of the package matching the prerelease parameter
/// </summary>
/// <value></value>
public SearchVersionInfo[] versions { get; set; }
public string description { get; set; }
public string[] authors { get; set; }
public string iconUrl { get; set; }
public string licenseUrl { get; set; }
public string projectUrl { get; set; }
/// <summary>
/// The absolute URL to the associated registration index
/// </summary>
/// <value></value>
public string registration { get; }
public string summary { get; set; }
public string[] tags { get; set; }
public string title { get; set; }
/// <summary>
/// This value can be inferred by the sum of downloads in the versions array
/// </summary>
/// <value></value>
public int totalDownloads { get; set; }
/// <summary>
/// boolean indicating whether the package is verified
/// </summary>
/// <value></value>
public bool verified { get; set; }
/// <summary>
/// The package types defined by the package author (added in SearchQueryService/3.5.0)
/// </summary>
/// <value></value>
[Required]
public PackageType[] packageTypes { get; set; }
[JsonProperty("id")]
public string PackageId { get; }
}
}

View File

@ -0,0 +1,70 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata.Ecma335;
using System.Text.Json.Serialization;
using System.Threading;
using isnd.Data;
using isnd.Data.Packages;
using isnd.Entities;
using NuGet.Packaging.Core;
namespace isnd.ViewModels
{
public class PackageSearchResult
{
public IEnumerable<Package> GetResults()
{
return result;
}
private IEnumerable<Package> result=null;
[JsonIgnore]
public string ApiBase{get; private set;}
public PackageSearchResult(string apiBase)
{
// empty result
this.ApiBase = apiBase;
}
public PackageSearchResult(IEnumerable<Package> result, string apiBase, int totalHit)
{
this.result = result;
this.ApiBase = apiBase;
data = (totalHit>0) ? result.Select(p=> NewPackageHit(apiBase, p)).ToArray()
: new PackageHit[0];
this.totalHits = totalHit;
}
private static PackageHit NewPackageHit(string apiBase, Package package)
{
string regId = $"{apiBase}{ApiConfig.Registration}/{package.Id}/index.json";
var latest = package.GetLatestVersion();
if (latest==null) return null;
var pkgHit = new PackageHit(regId, package.Id,
latest.NugetVersion.ToString(),
latest.Description);
if (package.Versions!=null)
{
pkgHit.versions = package.Versions
.Select(v => new SearchVersionInfo(apiBase, v)).ToArray();
pkgHit.packageTypes = package.Versions.Where(v=> v.Type!=null)
.Select(v=>new PackageType(v.Type, new System.Version(v.Major,v.Minor,v.Patch, v.Revision)))?.ToArray();
}
return pkgHit;
}
public PackageHit[] data { get; protected set; } = [];
public int totalHits { get; set; } = 0;
}
}

View File

@ -5,7 +5,8 @@ namespace isnd
{
public class RegistrationPageIndexQueryAndResult
{
public string Source { get; set; }
public PackageRegistrationQuery Query { get; set; }
public PackageRegistration[] Result { get; set; }
public Catalog[] Result { get; set; }
}
}

View File

@ -0,0 +1,23 @@
using isnd.Data.Catalog;
using isnd.Entities;
using Newtonsoft.Json;
namespace isnd.ViewModels
{
public class SearchVersionInfo: Permalink
{
public SearchVersionInfo(string apiBase, Data.PackageVersion v) : base( $"{apiBase}{ApiConfig.Registration}/{v.PackageId}/{v.FullString}.json", "VersionInfo")
{
Version = v.FullString;
}
[JsonProperty("version")]
public string Version { get; set; }
[JsonProperty("downloads")]
public long Downloads { get; set; }
}
}

View File

@ -1,4 +1,8 @@
@model string
@{
ViewData["Title"] = "Error";
}
<h1>@ViewData["Title"]</h1>
<p>@Model</p>

View File

@ -1,11 +1,10 @@
@model HomeIndexViewModel
@{
ViewData["Title"] = "Home Page";
ViewData["Title"] = "Packages";
}
<div class="text-center">
<h1 class="display-4">Bienvenue</h1>
<h1>Bienvenue dans isn</h1>
<p>
<strong>@Model.PkgCount identifiant(s) de paquet dans le SI</strong>
</p>
<h1 class="display-4">@ViewData["Title"]</h1>
<p></p>
<p>Nuget API v3 :
<a href="@Model.APIUrl"><code>@Model.APIUrl</code></a></p>
</div>

View File

@ -3,4 +3,10 @@
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>
<p>Your informations are only used in order to render the service,
that is, providing a NuGet package source, that trying and implement a V3 version of its API,
and a web access, with authentication needed, in case of package provider, or admin access.
</p>
<p>At the time of this writting, your email won't be used for anything else than the authentication validation,
your name's free, and as personal information, you'll face nothing more than technical requirment .
</p>

View File

@ -0,0 +1,12 @@
@{
ViewData["Title"] = "Politique concernant la vie privée";
}
<h1>@ViewData["Title"]</h1>
<p>Vos informations ne sont utilisées que pour rendre le service,
c'est à dire, fournire une source de paquets NuGet, qui essaye d'implémenter une version V3 de son API,
et un accès web, avec nécessité d'autentification, en cas d'accès de fournisseur de paquet, ou d'administrateur.
</p>
<p>À l'heure de cet écrit, votre email ne sera utilisé pour rien d'autre que la validation de votre autentification,
votre nom est libre, et comme informations personnelles, vous n'aurez affaire qu'à des prérequis techniques.
</p>

View File

@ -32,6 +32,5 @@
</dl>
</div>
<div>
@Html.ActionLink("Edit", "Edit", new { pkgid = Model.PackageId, version = Model.FullString }) |
<a asp-action="Index">Back to List</a>
</div>

View File

@ -1,4 +1,4 @@
@model isnd.Data.PackageVersion
@model PackageDetails
@{
ViewData["Title"] = "Delete";
@ -12,42 +12,43 @@
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.Major)
@Html.DisplayNameFor(model => model.Title)
</dt>
<dd>
@Html.DisplayFor(model => model.Major)
@Html.DisplayFor(model => model.Title)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Minor)
@Html.DisplayNameFor(model => model.Id)
</dt>
<dd>
@Html.DisplayFor(model => model.Minor)
@Html.DisplayFor(model => model.Id)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Patch)
@Html.DisplayNameFor(model => model.Version)
</dt>
<dd>
@Html.DisplayFor(model => model.Patch)
@Html.DisplayFor(model => model.Version)
</dd>
<dt>
@Html.DisplayNameFor(model => model.IsPrerelease)
@Html.DisplayNameFor(model => model.Description)
</dt>
<dd>
@Html.DisplayFor(model => model.IsPrerelease)
@Html.DisplayFor(model => model.Description)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Package)
@Html.DisplayNameFor(model => model.DownloadCount)
</dt>
<dd>
@Html.DisplayFor(model => model.Package.Id)
@Html.DisplayFor(model => model.DownloadCount)
</dd>
</dl>
@if (Model!=null) {
<form asp-action="DeleteConfirmed">
<input type="hidden" asp-for="PackageId" />
<input type="hidden" asp-for="FullString" />
<input type="hidden" asp-for="Type" />
<input type="hidden" name="pkgid" value="@Model.PackageId" />
<input type="hidden" name="version" value="@Model.Version" />
<input type="hidden" name="type" value="@Model.Type" />
<input type="submit" value="Delete" class="btn btn-default" /> |
<a asp-action="Index">Back to List</a>
</form>
}
</div>

View File

@ -37,9 +37,8 @@
<button class="far fa-copy" style="float:right" onclick="navigator.clipboard.writeText($('#code').text());this.innerText='copied'" >copy</button>
<pre><code id="code" >&lt;PackageReference Include="@Model.pkgid" Version="@Model.latest.FullString" /&gt;</code></pre>
</div>
<div>
@Html.ActionLink("Edit", "Edit", new { pkgid = Model.pkgid, version = Model.latest.FullString }) |
@Html.ActionLink("Delete", "Delete", new { pkgid = Model.pkgid, version= Model.latest.FullString }) |
<div class="controls">
@Html.ActionLink("Delete", "Delete", new { pkgid = Model.pkgid, version= Model.latest.FullString }) |
<a asp-action="Index">Back to List</a>
</div>
</div>

View File

@ -35,3 +35,6 @@ foreach (var i in regpage.Items) {
}
</tbody>
</table>
<p><pre><code>@Model.Source</code></pre></p>

View File

@ -4,19 +4,23 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - isn</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<link rel="stylesheet" href="~/css/site.css" />
<link rel="shortcut icon" href="favicon.ico#1" >
<link rel="stylesheet"
href="bower_components/bootstrap/dist/css/bootstrap.min.css" asp-append-version="true"/>
<link rel="shortcut icon" href="favicon.ico" asp-append-version="true" >
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
<header>
<nav class="navbar navbar-dark bg-dark navbar-expand-sm" >
<div class="container">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index"><img src="~/icon.png" alt="isn"></a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<button class="navbar-toggler" type="button" data-toggle="collapse"
data-target="#navbar" aria-controls="navbarSupportedContent" aria-expanded="true"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<div class="collapse navbar-collapse" id="navbar">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" asp-area="" asp-controller="Home" asp-action="Index">Home<span class="sr-only">(current)</span></a>
@ -29,7 +33,8 @@
<div class="navbar-item">
<form class="form-inline my-2 my-lg-0" asp-action="Index" asp-controller="Packages">
<input style="margin:.3em;" name="Query" id="Query" class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
<input style="margin:.3em;" name="IsPrerelease" id="IsPrerelease" class="form-control mr-sm-2" type="checkbox" checked><label for="IsPrerelease"> <i>Pre-release </i></Label>
<label for="IsPrerelease" class="navbar-item btn btn-outline-secondary"><i>Pre-release </i></Label>
<input style="margin:.3em;" name="IsPrerelease" id="IsPrerelease" type="checkbox" checked>
<button style="margin:.3em;" class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
@ -45,17 +50,15 @@
</main>
</div>
<footer class="border-top footer text-muted" style="position:bottom">
isn @SiteHelpers.SemVer &copy; 2021-2022 Paul Schneider - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
<footer class="border-top footer text-muted" style="position:bottom; text-align: center;">
isn @SiteHelpers.SemVer &copy; DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
</footer>
<!-- <script src="/lib/jquery/dist/jquery.slim.min.js" ></script>
<script src="/lib/popper/popper.min.js"></script>
<script src="/lib/bootstrap/dist/js/bootstrap.min.js" ></script> -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>

View File

@ -11,9 +11,6 @@
"MaxUserKeyCount": 1,
"CatalogPageLen": 480
},
"ConnectionStrings": {
"DefaultConnection": "Server=<pgserver>;Port=<pgport>;Database=<dbname>;Username=<dbusername>;Password=<dbpass>;"
},
"AllowedHosts": "*",
"Smtp": {
"Server": "<smtp.server.address>",

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<UserSecretsId>85fd766d-5d23-4476-aed1-463b2942e86a</UserSecretsId>
<IsPackable>true</IsPackable>
<PackageLicenseExpression>WTFPL</PackageLicenseExpression>
@ -13,32 +13,33 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="7.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.4">
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.10">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.4" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.10" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.6" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="7.0.4" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.3" IncludeAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.10" IncludeAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="NuGet.Packaging.Core" Version="6.5.0" />
<PackageReference Include="MailKit" Version="3.6.0" />
<PackageReference Include="unleash.client" Version="2.4.3" />
<PackageReference Include="GitVersion.MsBuild" Version="5.12.0">
<PackageReference Include="NuGet.Packaging.Core" Version="6.9.1" />
<PackageReference Include="MailKit" Version="4.8.0" />
<PackageReference Include="GitVersion.MsBuild" Version="6.0.3">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="7.0.1" />
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="8.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Antiforgery" Version="2.2.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../isn.abst/isn.abst.csproj" />

10
src/isnd/libman.json Normal file
View File

@ -0,0 +1,10 @@
{
"version": "1.0",
"defaultProvider": "cdnjs",
"libraries": [
{
"library": "jquery@2.2.4",
"destination": "wwwroot/lib/jquery"
}
]
}

View File

@ -0,0 +1,12 @@
module.exports = {
presets: [
[
'@babel/preset-env',
{
loose: true,
bugfixes: true,
modules: false
}
]
]
};

View File

@ -0,0 +1,15 @@
{
"name": "bootstrap",
"homepage": "https://github.com/twbs/bootstrap",
"version": "5.3.3",
"_release": "5.3.3",
"_resolution": {
"type": "version",
"tag": "v5.3.3",
"commit": "6e1f75f420f68e1d52733b8e407fc7c3766c9dba"
},
"_source": "https://github.com/twbs/bootstrap.git",
"_target": "^5.3.3",
"_originalSource": "bootstrap",
"_direct": true
}

View File

@ -0,0 +1,11 @@
# https://github.com/browserslist/browserslist#readme
>= 0.5%
last 2 major versions
not dead
Chrome >= 60
Firefox >= 60
Firefox ESR
iOS >= 12
Safari >= 12
not Explorer <= 11

View File

@ -0,0 +1,66 @@
{
"files": [
{
"path": "./dist/css/bootstrap-grid.css",
"maxSize": "6.5 kB"
},
{
"path": "./dist/css/bootstrap-grid.min.css",
"maxSize": "6.0 kB"
},
{
"path": "./dist/css/bootstrap-reboot.css",
"maxSize": "3.5 kB"
},
{
"path": "./dist/css/bootstrap-reboot.min.css",
"maxSize": "3.25 kB"
},
{
"path": "./dist/css/bootstrap-utilities.css",
"maxSize": "11.75 kB"
},
{
"path": "./dist/css/bootstrap-utilities.min.css",
"maxSize": "10.75 kB"
},
{
"path": "./dist/css/bootstrap.css",
"maxSize": "32.5 kB"
},
{
"path": "./dist/css/bootstrap.min.css",
"maxSize": "30.25 kB"
},
{
"path": "./dist/js/bootstrap.bundle.js",
"maxSize": "43.0 kB"
},
{
"path": "./dist/js/bootstrap.bundle.min.js",
"maxSize": "23.25 kB"
},
{
"path": "./dist/js/bootstrap.esm.js",
"maxSize": "28.0 kB"
},
{
"path": "./dist/js/bootstrap.esm.min.js",
"maxSize": "18.25 kB"
},
{
"path": "./dist/js/bootstrap.js",
"maxSize": "28.75 kB"
},
{
"path": "./dist/js/bootstrap.min.js",
"maxSize": "16.25 kB"
}
],
"ci": {
"trackBranches": [
"main",
"v4-dev"
]
}
}

View File

@ -0,0 +1,133 @@
{
"version": "0.2",
"words": [
"affordance",
"allowfullscreen",
"Analyser",
"autohide",
"autohiding",
"autoplay",
"autoplays",
"autoplaying",
"blazingly",
"Blockquotes",
"Bootstrappers",
"borderless",
"Brotli",
"browserslist",
"browserslistrc",
"btncheck",
"btnradio",
"callout",
"callouts",
"camelCase",
"clearfix",
"Codesniffer",
"combinator",
"Contentful",
"Cpath",
"Crossfade",
"crossfading",
"cssgrid",
"Csvg",
"Datalists",
"Deque",
"discoverability",
"docsearch",
"docsref",
"dropend",
"dropleft",
"dropright",
"dropstart",
"dropup",
"dgst",
"errorf",
"favicon",
"favicons",
"fieldsets",
"flexbox",
"fullscreen",
"getbootstrap",
"Grayscale",
"Hoverable",
"hreflang",
"hstack",
"importmap",
"jsdelivr",
"Jumpstart",
"keyframes",
"libera",
"libman",
"Libsass",
"lightboxes",
"Lowercased",
"markdownify",
"mediaqueries",
"minifiers",
"misfunction",
"mkdir",
"monospace",
"mouseleave",
"navbars",
"navs",
"Neue",
"noindex",
"Noto",
"offcanvas",
"offcanvases",
"Packagist",
"popperjs",
"prebuild",
"prefersreducedmotion",
"prepended",
"printf",
"rects",
"relref",
"rgba",
"roboto",
"RTLCSS",
"ruleset",
"screenreaders",
"scrollbars",
"scrollspy",
"Segoe",
"semibold",
"socio",
"srcset",
"stackblitz",
"stickied",
"Stylelint",
"subnav",
"tabbable",
"textareas",
"toggleable",
"topbar",
"touchend",
"twbs",
"unitless",
"unstylable",
"unstyled",
"Uppercased",
"urlize",
"urlquery",
"vbtn",
"viewports",
"Vite",
"vstack",
"walkthroughs",
"WCAG",
"zindex"
],
"language": "en-US",
"files": [
"**/*.md"
],
"ignorePaths": [
".cspell.json",
"dist/",
"*.min.*",
"**/*rtl*",
"**/tests/**"
],
"useGitignore": true
}

View File

@ -0,0 +1,11 @@
# editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

View File

@ -0,0 +1,7 @@
**/*.min.js
**/dist/
**/vendor/
/_site/
/js/coverage/
/site/static/sw.js
/site/layouts/partials/

View File

@ -0,0 +1,222 @@
{
"root": true,
"extends": [
"plugin:import/errors",
"plugin:import/warnings",
"plugin:unicorn/recommended",
"xo",
"xo/browser"
],
"rules": {
"arrow-body-style": "off",
"capitalized-comments": "off",
"comma-dangle": [
"error",
"never"
],
"import/extensions": [
"error",
"ignorePackages",
{
"js": "always"
}
],
"import/first": "error",
"import/newline-after-import": "error",
"import/no-absolute-path": "error",
"import/no-amd": "error",
"import/no-cycle": [
"error",
{
"ignoreExternal": true
}
],
"import/no-duplicates": "error",
"import/no-extraneous-dependencies": "error",
"import/no-mutable-exports": "error",
"import/no-named-as-default": "error",
"import/no-named-as-default-member": "error",
"import/no-named-default": "error",
"import/no-self-import": "error",
"import/no-unassigned-import": [
"error"
],
"import/no-useless-path-segments": "error",
"import/order": "error",
"indent": [
"error",
2,
{
"MemberExpression": "off",
"SwitchCase": 1
}
],
"logical-assignment-operators": "off",
"max-params": [
"warn",
5
],
"multiline-ternary": [
"error",
"always-multiline"
],
"new-cap": [
"error",
{
"properties": false
}
],
"no-console": "error",
"no-negated-condition": "off",
"object-curly-spacing": [
"error",
"always"
],
"operator-linebreak": [
"error",
"after"
],
"prefer-object-has-own": "off",
"prefer-template": "error",
"semi": [
"error",
"never"
],
"strict": "error",
"unicorn/explicit-length-check": "off",
"unicorn/filename-case": "off",
"unicorn/no-array-callback-reference": "off",
"unicorn/no-array-method-this-argument": "off",
"unicorn/no-null": "off",
"unicorn/no-typeof-undefined": "off",
"unicorn/no-unused-properties": "error",
"unicorn/numeric-separators-style": "off",
"unicorn/prefer-array-flat": "off",
"unicorn/prefer-at": "off",
"unicorn/prefer-dom-node-dataset": "off",
"unicorn/prefer-module": "off",
"unicorn/prefer-query-selector": "off",
"unicorn/prefer-spread": "off",
"unicorn/prefer-string-replace-all": "off",
"unicorn/prevent-abbreviations": "off"
},
"overrides": [
{
"files": [
"build/**"
],
"env": {
"browser": false,
"node": true
},
"parserOptions": {
"sourceType": "module"
},
"rules": {
"no-console": "off",
"unicorn/prefer-top-level-await": "off"
}
},
{
"files": [
"js/**"
],
"parserOptions": {
"sourceType": "module"
}
},
{
"files": [
"js/tests/*.js",
"js/tests/integration/rollup*.js"
],
"env": {
"node": true
},
"parserOptions": {
"sourceType": "script"
}
},
{
"files": [
"js/tests/unit/**"
],
"env": {
"jasmine": true
},
"rules": {
"no-console": "off",
"unicorn/consistent-function-scoping": "off",
"unicorn/no-useless-undefined": "off",
"unicorn/prefer-add-event-listener": "off"
}
},
{
"files": [
"js/tests/visual/**"
],
"plugins": [
"html"
],
"settings": {
"html/html-extensions": [
".html"
]
},
"rules": {
"no-console": "off",
"no-new": "off",
"unicorn/no-array-for-each": "off"
}
},
{
"files": [
"scss/tests/**"
],
"env": {
"node": true
},
"parserOptions": {
"sourceType": "script"
}
},
{
"files": [
"site/**"
],
"env": {
"browser": true,
"node": false
},
"parserOptions": {
"sourceType": "script",
"ecmaVersion": 2019
},
"rules": {
"no-new": "off",
"unicorn/no-array-for-each": "off"
}
},
{
"files": [
"**/*.md"
],
"plugins": [
"markdown"
],
"processor": "markdown/markdown"
},
{
"files": [
"**/*.md/*.js"
],
"extends": "plugin:markdown/recommended",
"parserOptions": {
"sourceType": "module"
},
"rules": {
"unicorn/prefer-node-protocol": "off"
}
}
]
}

Some files were not shown because too many files have changed in this diff Show More