Web Api layout
This commit is contained in:
parent
5619093f41
commit
da6d5576bf
32 changed files with 515 additions and 29 deletions
|
|
@ -7,6 +7,12 @@
|
||||||
"commands": [
|
"commands": [
|
||||||
"dotnet-ef"
|
"dotnet-ef"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"dotnet-aspnet-codegenerator": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"commands": [
|
||||||
|
"dotnet-aspnet-codegenerator"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -29,7 +29,7 @@ tab_width = 4
|
||||||
|
|
||||||
# New line preferences
|
# New line preferences
|
||||||
end_of_line = crlf
|
end_of_line = crlf
|
||||||
insert_final_newline = false
|
insert_final_newline = true
|
||||||
|
|
||||||
#### .NET Coding Conventions ####
|
#### .NET Coding Conventions ####
|
||||||
[*.{cs,vb}]
|
[*.{cs,vb}]
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,16 @@
|
||||||
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
|
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.ApiAuthorization.IdentityServer" Version="7.0.15" />
|
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.1" />
|
<PackageVersion Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.1" />
|
||||||
|
<PackageVersion Include="Microsoft.AspNetCore.Identity.UI" Version="8.0.1" />
|
||||||
|
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.1" />
|
||||||
|
<PackageVersion Include="Microsoft.EntityFrameworkCore.Abstractions" Version="8.0.1" />
|
||||||
|
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.1" />
|
||||||
|
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.1" />
|
||||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.1" />
|
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.1" />
|
||||||
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0" />
|
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.1" />
|
||||||
|
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.0" />
|
||||||
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||||
|
<PackageVersion Include="System.IO.Hashing" Version="8.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
36
InkForge.Api.Data/ApiDbContext.cs
Normal file
36
InkForge.Api.Data/ApiDbContext.cs
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
using InkForge.Api.Data.Infrastructure;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace InkForge.Api.Data;
|
||||||
|
|
||||||
|
public class ApiDbcontext(
|
||||||
|
DbContextOptions<ApiDbcontext> options
|
||||||
|
) : IdentityDbContext<IdentityUser>(options)
|
||||||
|
{
|
||||||
|
public DbSet<WorkspaceEntity> Workspaces { get; set; } = default!;
|
||||||
|
|
||||||
|
public DbSet<WorkspaceVersionEntity> WorkspaceVersions { get; set; } = default!;
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder builder)
|
||||||
|
{
|
||||||
|
base.OnModelCreating(builder);
|
||||||
|
|
||||||
|
builder.Entity<WorkspaceEntity>(options =>
|
||||||
|
{
|
||||||
|
options.OwnsOne(m => m.Value);
|
||||||
|
|
||||||
|
options.HasKey(m => m.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Entity<WorkspaceVersionEntity>(options =>
|
||||||
|
{
|
||||||
|
options.OwnsOne(m => m.Value);
|
||||||
|
|
||||||
|
options.HasKey(m => m.Version);
|
||||||
|
options.HasIndex(nameof(WorkspaceVersionEntity.Id), nameof(WorkspaceVersionEntity.Version)).IsUnique();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
16
InkForge.Api.Data/Domain/Workspace.cs
Normal file
16
InkForge.Api.Data/Domain/Workspace.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
|
||||||
|
namespace InkForge.Api.Data.Domain;
|
||||||
|
|
||||||
|
public class Workspace
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = default!;
|
||||||
|
|
||||||
|
public DateTimeOffset Created { get; set; }
|
||||||
|
|
||||||
|
public IdentityUser Owner { get; set; } = default!;
|
||||||
|
|
||||||
|
public DateTimeOffset Updated { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset? Deleted { get; set; }
|
||||||
|
}
|
||||||
9
InkForge.Api.Data/Infrastructure/WorkspaceEntities.cs
Normal file
9
InkForge.Api.Data/Infrastructure/WorkspaceEntities.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
using InkForge.Api.Data.Domain;
|
||||||
|
using InkForge.Data;
|
||||||
|
|
||||||
|
namespace InkForge.Api.Data.Infrastructure
|
||||||
|
{
|
||||||
|
public class WorkspaceEntity : Entity<Workspace, int>;
|
||||||
|
|
||||||
|
public class WorkspaceVersionEntity : VersionedEntity<Workspace, int>;
|
||||||
|
}
|
||||||
17
InkForge.Api.Data/InkForge.Api.Data.csproj
Normal file
17
InkForge.Api.Data/InkForge.Api.Data.csproj
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\shared\InkForge.Data\InkForge.Data.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
4
InkForge.Api/Areas/Identity/Pages/_ViewStart.cshtml
Normal file
4
InkForge.Api/Areas/Identity/Pages/_ViewStart.cshtml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
@{
|
||||||
|
Layout = "/Pages/Shared/_Layout.cshtml";
|
||||||
|
}
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
using Duende.IdentityServer.EntityFramework.Options;
|
|
||||||
|
|
||||||
using Microsoft.AspNetCore.ApiAuthorization.IdentityServer;
|
|
||||||
using Microsoft.AspNetCore.Identity;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
|
|
||||||
namespace InkForge.Api.Data;
|
|
||||||
|
|
||||||
public class ApiDbcontext(
|
|
||||||
DbContextOptions options,
|
|
||||||
IOptions<OperationalStoreOptions> operationalStoreOptions
|
|
||||||
) : ApiAuthorizationDbContext<IdentityUser>(options, operationalStoreOptions)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
@ -9,11 +9,16 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.ApiAuthorization.IdentityServer" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" />
|
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" />
|
<PackageReference Include="Swashbuckle.AspNetCore" />
|
||||||
|
<PackageReference Include="System.IO.Hashing" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\InkForge.Api.Data\InkForge.Api.Data.csproj" />
|
||||||
|
<ProjectReference Include="..\migrations\InkForge.Api.Sqlite\InkForge.Api.Sqlite.csproj" />
|
||||||
|
<ProjectReference Include="..\shared\InkForge.Data\InkForge.Data.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
94
InkForge.Api/Pages/Shared/_Layout.cshtml
Normal file
94
InkForge.Api/Pages/Shared/_Layout.cshtml
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
@using Microsoft.AspNetCore.Hosting
|
||||||
|
@using Microsoft.AspNetCore.Mvc.ViewEngines
|
||||||
|
@inject IWebHostEnvironment Environment
|
||||||
|
@inject ICompositeViewEngine Engine
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>@ViewData["Title"] - InkForge.Api</title>
|
||||||
|
|
||||||
|
<environment include="Development">
|
||||||
|
<link rel="stylesheet" href="~/Identity/lib/bootstrap/dist/css/bootstrap.css" />
|
||||||
|
<link rel="stylesheet" href="~/Identity/css/site.css" />
|
||||||
|
</environment>
|
||||||
|
<environment exclude="Development">
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css"
|
||||||
|
integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous"
|
||||||
|
asp-fallback-href="~/Identity/lib/bootstrap/dist/css/bootstrap.min.css"
|
||||||
|
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
|
||||||
|
<link rel="stylesheet" href="~/Identity/css/site.css" asp-append-version="true" />
|
||||||
|
</environment>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
|
||||||
|
<div class="container">
|
||||||
|
<a class="navbar-brand" href="~/">InkForge.Api</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
|
||||||
|
aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
|
||||||
|
@{
|
||||||
|
var result = Engine.FindView(ViewContext, "_LoginPartial", isMainPage: false);
|
||||||
|
}
|
||||||
|
@if (result.Success)
|
||||||
|
{
|
||||||
|
await Html.RenderPartialAsync("_LoginPartial");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("The default Identity UI layout requires a partial view '_LoginPartial' " +
|
||||||
|
"usually located at '/Pages/_LoginPartial' or at '/Views/Shared/_LoginPartial' to work. Based on your configuration " +
|
||||||
|
$"we have looked at it in the following locations: {System.Environment.NewLine}{string.Join(System.Environment.NewLine, result.SearchedLocations)}.");
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<partial name="_CookieConsentPartial" optional />
|
||||||
|
<main role="main" class="pb-1">
|
||||||
|
@RenderBody()
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
<footer class="footer border-top pl-3 text-muted">
|
||||||
|
<div class="container">
|
||||||
|
© 2024 - InkForge.Api
|
||||||
|
@{
|
||||||
|
var foundPrivacy = Url.Page("/Privacy", new { area = "" });
|
||||||
|
}
|
||||||
|
@if (foundPrivacy != null)
|
||||||
|
{
|
||||||
|
<a asp-area="" asp-page="/Privacy">Privacy</a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<environment include="Development">
|
||||||
|
<script src="~/Identity/lib/jquery/dist/jquery.js"></script>
|
||||||
|
<script src="~/Identity/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
|
||||||
|
<script src="~/Identity/js/site.js" asp-append-version="true"></script>
|
||||||
|
</environment>
|
||||||
|
<environment exclude="Development">
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"
|
||||||
|
asp-fallback-src="~/Identity/lib/jquery/dist/jquery.min.js"
|
||||||
|
asp-fallback-test="window.jQuery"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
integrity="sha384-ZvpUoO/+PpLXR1lu4jmpXWu80pZlYUAfxl5NsBMWOEPSjUn/6Z/hRTt8+pR6L4N2">
|
||||||
|
</script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/js/bootstrap.bundle.min.js"
|
||||||
|
asp-fallback-src="~/Identity/lib/bootstrap/dist/js/bootstrap.bundle.min.js"
|
||||||
|
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
integrity="sha384-U1DAWAznBHeqEIlVSCgzq+c9gqGAJn5c/t99JyeKa9xxaYpSvHU5awsuZVVFIhvj">
|
||||||
|
</script>
|
||||||
|
<script src="~/Identity/js/site.js" asp-append-version="true"></script>
|
||||||
|
</environment>
|
||||||
|
|
||||||
|
@await RenderSectionAsync("Scripts", required: false)
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
27
InkForge.Api/Pages/Shared/_LoginPartial.cshtml
Normal file
27
InkForge.Api/Pages/Shared/_LoginPartial.cshtml
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
@using Microsoft.AspNetCore.Identity
|
||||||
|
|
||||||
|
@inject SignInManager<IdentityUser> SignInManager
|
||||||
|
@inject UserManager<IdentityUser> UserManager
|
||||||
|
|
||||||
|
<ul class="navbar-nav">
|
||||||
|
@if (SignInManager.IsSignedIn(User))
|
||||||
|
{
|
||||||
|
<li class="nav-item">
|
||||||
|
<a id="manage" class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage">Hello @UserManager.GetUserName(User)!</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<form id="logoutForm" class="form-inline" asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="@Url.Action("Index", "Home", new { area = "" })">
|
||||||
|
<button id="logout" type="submit" class="nav-link btn btn-link text-dark border-0">Logout</button>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link text-dark" id="register" asp-area="Identity" asp-page="/Account/Register">Register</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link text-dark" id="login" asp-area="Identity" asp-page="/Account/Login">Login</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
18
InkForge.Api/Pages/Shared/_ValidationScriptsPartial.cshtml
Normal file
18
InkForge.Api/Pages/Shared/_ValidationScriptsPartial.cshtml
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
<environment include="Development">
|
||||||
|
<script src="~/Identity/lib/jquery-validation/dist/jquery.validate.js"></script>
|
||||||
|
<script src="~/Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
|
||||||
|
</environment>
|
||||||
|
<environment exclude="Development">
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.min.js"
|
||||||
|
asp-fallback-src="~/Identity/lib/jquery-validation/dist/jquery.validate.min.js"
|
||||||
|
asp-fallback-test="window.jQuery && window.jQuery.validator"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
integrity="sha384-rZfj/ogBloos6wzLGpPkkOr/gpkBNLZ6b6yLy4o+ok+t/SAKlL5mvXLr0OXNi1Hp">
|
||||||
|
</script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js"
|
||||||
|
asp-fallback-src="~/Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"
|
||||||
|
asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
integrity="sha384-R3vNCHsZ+A2Lo3d5A6XNP7fdQkeswQWTIPfiYwSpEP3YV079R+93YzTeZRah7f/F">
|
||||||
|
</script>
|
||||||
|
</environment>
|
||||||
6
InkForge.Api/Pages/_ViewImports.cshtml
Normal file
6
InkForge.Api/Pages/_ViewImports.cshtml
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
@using Microsoft.AspNetCore.Identity
|
||||||
|
@using InkForge.Api.Data
|
||||||
|
|
||||||
|
|
||||||
|
InkForge.Api.Pages
|
||||||
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
3
InkForge.Api/Pages/_ViewStart.cshtml
Normal file
3
InkForge.Api/Pages/_ViewStart.cshtml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
@{
|
||||||
|
Layout = "_Layout";
|
||||||
|
}
|
||||||
|
|
@ -1,17 +1,31 @@
|
||||||
using Microsoft.AspNetCore.Identity;
|
|
||||||
|
|
||||||
using InkForge.Api.Data;
|
using InkForge.Api.Data;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
|
|
||||||
|
builder.Services.AddHttpClient();
|
||||||
|
builder.Services.AddIdentityApiEndpoints<IdentityUser>()
|
||||||
|
.AddEntityFrameworkStores<ApiDbcontext>()
|
||||||
|
.AddDefaultUI().AddDefaultTokenProviders();
|
||||||
|
var provider = builder.Configuration.GetValue<string>("DbProvider");
|
||||||
|
builder.Services.AddDbContext<ApiDbcontext>(options => _ = provider switch
|
||||||
|
{
|
||||||
|
"Sqlite" => options.UseSqlite(
|
||||||
|
builder.Configuration.GetConnectionString("AuthDb"),
|
||||||
|
x => x.MigrationsAssembly("InkForge.Api.Sqlite")
|
||||||
|
),
|
||||||
|
|
||||||
|
_ => throw new Exception($"Invalid Provider: {provider}")
|
||||||
|
});
|
||||||
|
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
builder.Services.AddSwaggerGen();
|
builder.Services.AddSwaggerGen();
|
||||||
builder.Services.AddIdentityApiEndpoints<IdentityUser>()
|
|
||||||
.AddEntityFrameworkStores<ApiDbcontext>();
|
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
|
|
@ -23,11 +37,15 @@ if (app.Environment.IsDevelopment())
|
||||||
}
|
}
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
|
app.UseStaticFiles();
|
||||||
|
|
||||||
|
app.UseRouting();
|
||||||
|
|
||||||
|
app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.MapIdentityApi<IdentityUser>();
|
app.MapIdentityApi<IdentityUser>();
|
||||||
|
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
|
app.MapRazorPages();
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
|
|
|
||||||
|
|
@ -4,5 +4,10 @@
|
||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Warning"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"DbProvider": "Sqlite",
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"AuthDb": "Data Source=Identity.db",
|
||||||
|
"WorkspaceDbTemplate": "Data Source=Workspaces/{WorkspaceId}.db"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,10 @@
|
||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Warning"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"DbProvider": "",
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"AuthDb": "",
|
||||||
|
"WorkspaceDbTemplate": ""
|
||||||
|
},
|
||||||
"AllowedHosts": "*"
|
"AllowedHosts": "*"
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<RootNamespace>InkForge.Desktop</RootNamespace>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
|
||||||
2
app/InkForge.Desktop/Program.cs
Normal file
2
app/InkForge.Desktop/Program.cs
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
// See https://aka.ms/new-console-template for more information
|
||||||
|
Console.WriteLine("Hello, World!");
|
||||||
23
design/InkForge.Migrations/ApiDbContextFactory.cs
Normal file
23
design/InkForge.Migrations/ApiDbContextFactory.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
using InkForge.Api.Data;
|
||||||
|
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace InkForge.Migrations;
|
||||||
|
|
||||||
|
public class ApiDbContextFactory : MigratingDbContextFactory<ApiDbcontext>
|
||||||
|
{
|
||||||
|
protected override void Configure(
|
||||||
|
DbContextOptionsBuilder<ApiDbcontext> optionsBuilder,
|
||||||
|
string connectionString,
|
||||||
|
string provider
|
||||||
|
) => _ = provider switch
|
||||||
|
{
|
||||||
|
"Sqlite" => optionsBuilder.UseSqlite(connectionString,
|
||||||
|
m => m.MigrationsAssembly("InkForge.Api.Sqlite")
|
||||||
|
),
|
||||||
|
|
||||||
|
_ => throw new Exception($"Invalid DbProvider: {provider}")
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override ApiDbcontext CreateDbContext(DbContextOptions<ApiDbcontext> options) => new(options);
|
||||||
|
}
|
||||||
24
design/InkForge.Migrations/InkForge.Migrations.csproj
Normal file
24
design/InkForge.Migrations/InkForge.Migrations.csproj
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\migrations\InkForge.Api.Sqlite\InkForge.Api.Sqlite.csproj" />
|
||||||
|
<ProjectReference Include="..\..\shared\migrations\InkForge.Sqlite\InkForge.Sqlite.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
32
design/InkForge.Migrations/MigratingDbContextFactory.cs
Normal file
32
design/InkForge.Migrations/MigratingDbContextFactory.cs
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Design;
|
||||||
|
|
||||||
|
namespace InkForge.Migrations;
|
||||||
|
|
||||||
|
public abstract class MigratingDbContextFactory<T> : IDesignTimeDbContextFactory<T>
|
||||||
|
where T : DbContext
|
||||||
|
{
|
||||||
|
public T CreateDbContext(string[] args)
|
||||||
|
{
|
||||||
|
var configuration = new ConfigurationBuilder()
|
||||||
|
.AddCommandLine(args)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var options = new DbContextOptionsBuilder<T>();
|
||||||
|
switch (configuration.GetValue<string>("DbProvider"))
|
||||||
|
{
|
||||||
|
case null:
|
||||||
|
throw new Exception("DbProvider not set.");
|
||||||
|
|
||||||
|
case { } provider:
|
||||||
|
Configure(options, configuration.GetConnectionString("DefaultConnection")!, provider);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateDbContext(options.Options);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void Configure(DbContextOptionsBuilder<T> optionsBuilder, string connectionString, string provider);
|
||||||
|
|
||||||
|
protected abstract T CreateDbContext(DbContextOptions<T> options);
|
||||||
|
}
|
||||||
23
design/InkForge.Migrations/NoteDbContextFactory.cs
Normal file
23
design/InkForge.Migrations/NoteDbContextFactory.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
using InkForge.Data;
|
||||||
|
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace InkForge.Migrations;
|
||||||
|
|
||||||
|
public class NoteDbContextFactory : MigratingDbContextFactory<NoteDbContext>
|
||||||
|
{
|
||||||
|
protected override void Configure(
|
||||||
|
DbContextOptionsBuilder<NoteDbContext> optionsBuilder,
|
||||||
|
string connectionString,
|
||||||
|
string provider
|
||||||
|
) => _ = provider switch
|
||||||
|
{
|
||||||
|
"Sqlite" => optionsBuilder.UseSqlite(connectionString,
|
||||||
|
m => m.MigrationsAssembly("InkForge.Sqlite")
|
||||||
|
),
|
||||||
|
|
||||||
|
_ => throw new Exception($"Invalid DbProvider: {provider}")
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override NoteDbContext CreateDbContext(DbContextOptions<NoteDbContext> options) => new(options);
|
||||||
|
}
|
||||||
17
migrations/InkForge.Api.Sqlite/InkForge.Api.Sqlite.csproj
Normal file
17
migrations/InkForge.Api.Sqlite/InkForge.Api.Sqlite.csproj
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\InkForge.Api.Data\InkForge.Api.Data.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
18
shared/InkForge.Data/Domain/Note.cs
Normal file
18
shared/InkForge.Data/Domain/Note.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
using InkForge.Data.Infrastructure;
|
||||||
|
|
||||||
|
namespace InkForge.Data.Domain;
|
||||||
|
|
||||||
|
public class Note
|
||||||
|
{
|
||||||
|
public DateTimeOffset Created { get; set; }
|
||||||
|
|
||||||
|
public NoteEntity? Parent { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; } = default!;
|
||||||
|
|
||||||
|
public DateTimeOffset Updated { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset? Deleted { get; set; }
|
||||||
|
|
||||||
|
public Blob Content { get; set; } = default!;
|
||||||
|
}
|
||||||
8
shared/InkForge.Data/Infrastructure/Blob.cs
Normal file
8
shared/InkForge.Data/Infrastructure/Blob.cs
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace InkForge.Data;
|
||||||
|
|
||||||
|
public class Blob
|
||||||
|
{
|
||||||
|
public string Id { get; set; } = default!;
|
||||||
|
|
||||||
|
public byte[] Content { get; set; } = default!;
|
||||||
|
}
|
||||||
25
shared/InkForge.Data/Infrastructure/Entities.cs
Normal file
25
shared/InkForge.Data/Infrastructure/Entities.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace InkForge.Data
|
||||||
|
{
|
||||||
|
public abstract class ValueEntity<TEntity>
|
||||||
|
{
|
||||||
|
public TEntity Value { get; set; } = default!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class Entity<TEntity, TKey>
|
||||||
|
: ValueEntity<TEntity>
|
||||||
|
where TKey : struct, INumber<TKey>
|
||||||
|
{
|
||||||
|
public TKey? Id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class VersionedEntity<TEntity, TKey>
|
||||||
|
: ValueEntity<TEntity>
|
||||||
|
where TKey : struct, INumber<TKey>
|
||||||
|
{
|
||||||
|
public TKey Id { get; set; }
|
||||||
|
|
||||||
|
public int? Version { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
8
shared/InkForge.Data/Infrastructure/NoteEntities.cs
Normal file
8
shared/InkForge.Data/Infrastructure/NoteEntities.cs
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
using InkForge.Data.Domain;
|
||||||
|
|
||||||
|
namespace InkForge.Data.Infrastructure
|
||||||
|
{
|
||||||
|
public class NoteEntity : Entity<Note, int>;
|
||||||
|
|
||||||
|
public class NoteVersionEntity : VersionedEntity<Note, int>;
|
||||||
|
}
|
||||||
|
|
@ -7,4 +7,8 @@
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
34
shared/InkForge.Data/NoteDbContext.cs
Normal file
34
shared/InkForge.Data/NoteDbContext.cs
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
using InkForge.Data.Infrastructure;
|
||||||
|
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace InkForge.Data;
|
||||||
|
|
||||||
|
public class NoteDbContext(
|
||||||
|
DbContextOptions<NoteDbContext> options
|
||||||
|
) : DbContext(options)
|
||||||
|
{
|
||||||
|
public DbSet<Blob> Blobs { get; set; } = default!;
|
||||||
|
|
||||||
|
public DbSet<NoteEntity> Notes { get; set; } = default!;
|
||||||
|
|
||||||
|
public DbSet<NoteVersionEntity> NoteVersions { get; set; } = default!;
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder.Entity<NoteEntity>(options =>
|
||||||
|
{
|
||||||
|
options.OwnsOne(m => m.Value);
|
||||||
|
|
||||||
|
options.HasKey(m => m.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity<NoteVersionEntity>(options =>
|
||||||
|
{
|
||||||
|
options.OwnsOne(m => m.Value);
|
||||||
|
options.Property(m => m.Id).IsRequired();
|
||||||
|
options.HasKey(m => m.Version);
|
||||||
|
options.HasIndex(nameof(NoteVersionEntity.Id), nameof(NoteVersionEntity.Version)).IsUnique();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,4 +7,12 @@
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
</Project>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\InkForge.Data\InkForge.Data.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue