Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d79ee1671d | |||
| 708aa3991a | |||
| b3e578308f | |||
| 58e562adb1 | |||
| fe294e288a | |||
| dd2d47e57d | |||
| ee4d6cb5b1 | |||
| 9030b332a1 | |||
| 2987f530fd | |||
| 0e03e41ee2 | |||
| a41abf4f11 | |||
| ab505dbad5 | |||
| f636392e52 |
+11
@@ -0,0 +1,11 @@
|
|||||||
|
# SQLite Datenbanken und Journal-Dateien
|
||||||
|
*.db
|
||||||
|
*.db-shm
|
||||||
|
*.db-wal
|
||||||
|
|
||||||
|
# Build-Artefakte
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
*.user
|
||||||
|
*.suo
|
||||||
|
*.vs/
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<MudNavMenu>
|
|
||||||
<MudText Typo="Typo.h6" Class="px-4 mt-4 mb-2">Navigation</MudText>
|
|
||||||
<MudDivider Class="mb-2" />
|
|
||||||
<MudNavLink Href="" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.CalendarMonth">Wochenübersicht</MudNavLink>
|
|
||||||
<MudNavLink Href="month" Icon="@Icons.Material.Filled.CalendarViewMonth">Monatsübersicht</MudNavLink>
|
|
||||||
<MudNavLink Href="feiertage" Icon="@Icons.Material.Filled.Celebration">Feiertage</MudNavLink>
|
|
||||||
<MudNavLink Href="urlaub-maximizer" Icon="@Icons.Material.Filled.AutoAwesome">Urlaubs-Maximizer</MudNavLink>
|
|
||||||
<MudNavLink Href="settings" Icon="@Icons.Material.Filled.Settings">Einstellungen</MudNavLink>
|
|
||||||
<MudDivider Class="mt-2 mb-2" />
|
|
||||||
<AuthorizeView>
|
|
||||||
<Authorized>
|
|
||||||
<MudStack Row="true" AlignItems="AlignItems.Center" Class="px-4 py-1" Spacing="1">
|
|
||||||
<MudIcon Icon="@Icons.Material.Filled.AccountCircle" Color="Color.Primary" Size="Size.Small" />
|
|
||||||
<MudText Typo="Typo.body2" Style="font-weight:600">@context.User.Identity?.Name</MudText>
|
|
||||||
</MudStack>
|
|
||||||
<MudNavLink Href="/auth/logout" Icon="@Icons.Material.Filled.Logout">Abmelden</MudNavLink>
|
|
||||||
</Authorized>
|
|
||||||
</AuthorizeView>
|
|
||||||
</MudNavMenu>
|
|
||||||
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
<script type="module" src="@Assets["Components/Layout/ReconnectModal.razor.js"]"></script>
|
|
||||||
|
|
||||||
<dialog id="components-reconnect-modal" data-nosnippet>
|
|
||||||
<div class="components-reconnect-container">
|
|
||||||
<div class="components-rejoining-animation" aria-hidden="true">
|
|
||||||
<div></div>
|
|
||||||
<div></div>
|
|
||||||
</div>
|
|
||||||
<p class="components-reconnect-first-attempt-visible">
|
|
||||||
Rejoining the server...
|
|
||||||
</p>
|
|
||||||
<p class="components-reconnect-repeated-attempt-visible">
|
|
||||||
Rejoin failed... trying again in <span id="components-seconds-to-next-attempt"></span> seconds.
|
|
||||||
</p>
|
|
||||||
<p class="components-reconnect-failed-visible">
|
|
||||||
Failed to rejoin.<br />Please retry or reload the page.
|
|
||||||
</p>
|
|
||||||
<button id="components-reconnect-button" class="components-reconnect-failed-visible">
|
|
||||||
Retry
|
|
||||||
</button>
|
|
||||||
<p class="components-pause-visible">
|
|
||||||
The session has been paused by the server.
|
|
||||||
</p>
|
|
||||||
<p class="components-resume-failed-visible">
|
|
||||||
Failed to resume the session.<br />Please retry or reload the page.
|
|
||||||
</p>
|
|
||||||
<button id="components-resume-button" class="components-pause-visible components-resume-failed-visible">
|
|
||||||
Resume
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</dialog>
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
.components-reconnect-first-attempt-visible,
|
|
||||||
.components-reconnect-repeated-attempt-visible,
|
|
||||||
.components-reconnect-failed-visible,
|
|
||||||
.components-pause-visible,
|
|
||||||
.components-resume-failed-visible,
|
|
||||||
.components-rejoining-animation {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible,
|
|
||||||
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation,
|
|
||||||
#components-reconnect-modal.components-reconnect-paused .components-pause-visible,
|
|
||||||
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible,
|
|
||||||
#components-reconnect-modal.components-reconnect-retrying,
|
|
||||||
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible,
|
|
||||||
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation,
|
|
||||||
#components-reconnect-modal.components-reconnect-failed,
|
|
||||||
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#components-reconnect-modal {
|
|
||||||
background-color: white;
|
|
||||||
width: 20rem;
|
|
||||||
margin: 20vh auto;
|
|
||||||
padding: 2rem;
|
|
||||||
border: 0;
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
box-shadow: 0 3px 6px 2px rgba(0, 0, 0, 0.3);
|
|
||||||
opacity: 0;
|
|
||||||
transition: display 0.5s allow-discrete, overlay 0.5s allow-discrete;
|
|
||||||
animation: components-reconnect-modal-fadeOutOpacity 0.5s both;
|
|
||||||
&[open]
|
|
||||||
|
|
||||||
{
|
|
||||||
animation: components-reconnect-modal-slideUp 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity 0.5s ease-in-out 0.3s;
|
|
||||||
animation-fill-mode: both;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#components-reconnect-modal::backdrop {
|
|
||||||
background-color: rgba(0, 0, 0, 0.4);
|
|
||||||
animation: components-reconnect-modal-fadeInOpacity 0.5s ease-in-out;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes components-reconnect-modal-slideUp {
|
|
||||||
0% {
|
|
||||||
transform: translateY(30px) scale(0.95);
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes components-reconnect-modal-fadeInOpacity {
|
|
||||||
0% {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes components-reconnect-modal-fadeOutOpacity {
|
|
||||||
0% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.components-reconnect-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#components-reconnect-modal p {
|
|
||||||
margin: 0;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#components-reconnect-modal button {
|
|
||||||
border: 0;
|
|
||||||
background-color: #6b9ed2;
|
|
||||||
color: white;
|
|
||||||
padding: 4px 24px;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#components-reconnect-modal button:hover {
|
|
||||||
background-color: #3b6ea2;
|
|
||||||
}
|
|
||||||
|
|
||||||
#components-reconnect-modal button:active {
|
|
||||||
background-color: #6b9ed2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.components-rejoining-animation {
|
|
||||||
position: relative;
|
|
||||||
width: 80px;
|
|
||||||
height: 80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.components-rejoining-animation div {
|
|
||||||
position: absolute;
|
|
||||||
border: 3px solid #0087ff;
|
|
||||||
opacity: 1;
|
|
||||||
border-radius: 50%;
|
|
||||||
animation: components-rejoining-animation 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.components-rejoining-animation div:nth-child(2) {
|
|
||||||
animation-delay: -0.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes components-rejoining-animation {
|
|
||||||
0% {
|
|
||||||
top: 40px;
|
|
||||||
left: 40px;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
4.9% {
|
|
||||||
top: 40px;
|
|
||||||
left: 40px;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
5% {
|
|
||||||
top: 40px;
|
|
||||||
left: 40px;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
top: 0px;
|
|
||||||
left: 0px;
|
|
||||||
width: 80px;
|
|
||||||
height: 80px;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
// Set up event handlers
|
|
||||||
const reconnectModal = document.getElementById("components-reconnect-modal");
|
|
||||||
reconnectModal.addEventListener("components-reconnect-state-changed", handleReconnectStateChanged);
|
|
||||||
|
|
||||||
const retryButton = document.getElementById("components-reconnect-button");
|
|
||||||
retryButton.addEventListener("click", retry);
|
|
||||||
|
|
||||||
const resumeButton = document.getElementById("components-resume-button");
|
|
||||||
resumeButton.addEventListener("click", resume);
|
|
||||||
|
|
||||||
function handleReconnectStateChanged(event) {
|
|
||||||
if (event.detail.state === "show") {
|
|
||||||
reconnectModal.showModal();
|
|
||||||
} else if (event.detail.state === "hide") {
|
|
||||||
reconnectModal.close();
|
|
||||||
} else if (event.detail.state === "failed") {
|
|
||||||
document.addEventListener("visibilitychange", retryWhenDocumentBecomesVisible);
|
|
||||||
} else if (event.detail.state === "rejected") {
|
|
||||||
location.reload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function retry() {
|
|
||||||
document.removeEventListener("visibilitychange", retryWhenDocumentBecomesVisible);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Reconnect will asynchronously return:
|
|
||||||
// - true to mean success
|
|
||||||
// - false to mean we reached the server, but it rejected the connection (e.g., unknown circuit ID)
|
|
||||||
// - exception to mean we didn't reach the server (this can be sync or async)
|
|
||||||
const successful = await Blazor.reconnect();
|
|
||||||
if (!successful) {
|
|
||||||
// We have been able to reach the server, but the circuit is no longer available.
|
|
||||||
// We'll reload the page so the user can continue using the app as quickly as possible.
|
|
||||||
const resumeSuccessful = await Blazor.resumeCircuit();
|
|
||||||
if (!resumeSuccessful) {
|
|
||||||
location.reload();
|
|
||||||
} else {
|
|
||||||
reconnectModal.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
// We got an exception, server is currently unavailable
|
|
||||||
document.addEventListener("visibilitychange", retryWhenDocumentBecomesVisible);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function resume() {
|
|
||||||
try {
|
|
||||||
const successful = await Blazor.resumeCircuit();
|
|
||||||
if (!successful) {
|
|
||||||
location.reload();
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
reconnectModal.classList.replace("components-reconnect-paused", "components-reconnect-resume-failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function retryWhenDocumentBecomesVisible() {
|
|
||||||
if (document.visibilityState === "visible") {
|
|
||||||
await retry();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
@page "/login"
|
|
||||||
@rendermode InteractiveServer
|
|
||||||
@attribute [AllowAnonymous]
|
|
||||||
@inject NavigationManager Nav
|
|
||||||
@inject ISnackbar Snackbar
|
|
||||||
|
|
||||||
<PageTitle>Anmelden – Timetracker</PageTitle>
|
|
||||||
|
|
||||||
<MudContainer MaxWidth="MaxWidth.Small" Class="mt-16">
|
|
||||||
<MudStack AlignItems="AlignItems.Center" Spacing="4">
|
|
||||||
|
|
||||||
@* ── Logo / Header ── *@
|
|
||||||
<MudStack AlignItems="AlignItems.Center" Spacing="1">
|
|
||||||
<MudIcon Icon="@Icons.Material.Filled.AccessTime"
|
|
||||||
Style="font-size:4rem; color:#1565C0" />
|
|
||||||
<MudText Typo="Typo.h4" Style="font-weight:700; color:#1565C0">Timetracker</MudText>
|
|
||||||
</MudStack>
|
|
||||||
|
|
||||||
<MudPaper Elevation="4" Class="pa-6 rounded-xl" Style="width:100%">
|
|
||||||
<MudTabs @bind-ActivePanelIndex="_activeTab" Rounded="true" Centered="true" Color="Color.Primary">
|
|
||||||
|
|
||||||
@* ── Login ── *@
|
|
||||||
<MudTabPanel Text="Anmelden">
|
|
||||||
<MudStack Spacing="3" Class="mt-4">
|
|
||||||
@if (_error != null && _activeTab == 0)
|
|
||||||
{
|
|
||||||
<MudAlert Severity="Severity.Error" Dense="true">@_error</MudAlert>
|
|
||||||
}
|
|
||||||
<form action="/auth/login" method="post">
|
|
||||||
<MudStack Spacing="3">
|
|
||||||
<MudTextField @bind-Value="_loginUsername"
|
|
||||||
Label="Benutzername"
|
|
||||||
Variant="Variant.Outlined"
|
|
||||||
Adornment="Adornment.Start"
|
|
||||||
AdornmentIcon="@Icons.Material.Filled.Person"
|
|
||||||
name="username"
|
|
||||||
AutoFocus="true" />
|
|
||||||
<MudTextField @bind-Value="_loginPassword"
|
|
||||||
Label="Passwort"
|
|
||||||
Variant="Variant.Outlined"
|
|
||||||
Adornment="Adornment.Start"
|
|
||||||
AdornmentIcon="@Icons.Material.Filled.Lock"
|
|
||||||
InputType="@(_showLoginPw ? InputType.Text : InputType.Password)"
|
|
||||||
AdornmentAriaLabel="Passwort anzeigen"
|
|
||||||
name="password"
|
|
||||||
OnAdornmentClick="@(() => _showLoginPw = !_showLoginPw)" />
|
|
||||||
<MudButton ButtonType="ButtonType.Submit"
|
|
||||||
Variant="Variant.Filled"
|
|
||||||
Color="Color.Primary"
|
|
||||||
FullWidth="true"
|
|
||||||
Size="Size.Large"
|
|
||||||
StartIcon="@Icons.Material.Filled.Login">
|
|
||||||
Anmelden
|
|
||||||
</MudButton>
|
|
||||||
</MudStack>
|
|
||||||
</form>
|
|
||||||
</MudStack>
|
|
||||||
</MudTabPanel>
|
|
||||||
|
|
||||||
@* ── Registrieren ── *@
|
|
||||||
<MudTabPanel Text="Registrieren">
|
|
||||||
<MudStack Spacing="3" Class="mt-4">
|
|
||||||
@if (_error != null && _activeTab == 1)
|
|
||||||
{
|
|
||||||
<MudAlert Severity="Severity.Error" Dense="true">@_error</MudAlert>
|
|
||||||
}
|
|
||||||
<form action="/auth/register" method="post">
|
|
||||||
<MudStack Spacing="3">
|
|
||||||
<MudTextField @bind-Value="_regUsername"
|
|
||||||
Label="Benutzername"
|
|
||||||
Variant="Variant.Outlined"
|
|
||||||
Adornment="Adornment.Start"
|
|
||||||
AdornmentIcon="@Icons.Material.Filled.Person"
|
|
||||||
name="username"
|
|
||||||
HelperText="Mindestens 3 Zeichen" />
|
|
||||||
<MudTextField @bind-Value="_regPassword"
|
|
||||||
Label="Passwort"
|
|
||||||
Variant="Variant.Outlined"
|
|
||||||
Adornment="Adornment.Start"
|
|
||||||
AdornmentIcon="@Icons.Material.Filled.Lock"
|
|
||||||
InputType="@(_showRegPw ? InputType.Text : InputType.Password)"
|
|
||||||
AdornmentAriaLabel="Passwort anzeigen"
|
|
||||||
name="password"
|
|
||||||
HelperText="Mindestens 6 Zeichen"
|
|
||||||
OnAdornmentClick="@(() => _showRegPw = !_showRegPw)" />
|
|
||||||
<MudButton ButtonType="ButtonType.Submit"
|
|
||||||
Variant="Variant.Filled"
|
|
||||||
Color="Color.Secondary"
|
|
||||||
FullWidth="true"
|
|
||||||
Size="Size.Large"
|
|
||||||
StartIcon="@Icons.Material.Filled.PersonAdd">
|
|
||||||
Konto erstellen
|
|
||||||
</MudButton>
|
|
||||||
</MudStack>
|
|
||||||
</form>
|
|
||||||
</MudStack>
|
|
||||||
</MudTabPanel>
|
|
||||||
|
|
||||||
</MudTabs>
|
|
||||||
</MudPaper>
|
|
||||||
</MudStack>
|
|
||||||
</MudContainer>
|
|
||||||
|
|
||||||
@code {
|
|
||||||
private int _activeTab = 0;
|
|
||||||
private string? _error;
|
|
||||||
private string _loginUsername = "";
|
|
||||||
private string _loginPassword = "";
|
|
||||||
private string _regUsername = "";
|
|
||||||
private string _regPassword = "";
|
|
||||||
private bool _showLoginPw;
|
|
||||||
private bool _showRegPw;
|
|
||||||
|
|
||||||
[SupplyParameterFromQuery(Name = "error")]
|
|
||||||
public string? ErrorParam { get; set; }
|
|
||||||
|
|
||||||
[SupplyParameterFromQuery(Name = "tab")]
|
|
||||||
public string? TabParam { get; set; }
|
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
|
||||||
{
|
|
||||||
_error = ErrorParam switch
|
|
||||||
{
|
|
||||||
"invalid" => "Benutzername oder Passwort falsch.",
|
|
||||||
not null => Uri.UnescapeDataString(ErrorParam),
|
|
||||||
_ => null
|
|
||||||
};
|
|
||||||
_activeTab = TabParam == "register" ? 1 : 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-114
@@ -1,114 +0,0 @@
|
|||||||
using System.Security.Claims;
|
|
||||||
using Microsoft.AspNetCore.Authentication;
|
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using MudBlazor.Services;
|
|
||||||
using timetracker.Components;
|
|
||||||
using timetracker.Data;
|
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
|
||||||
|
|
||||||
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
|
|
||||||
.AddCookie(options =>
|
|
||||||
{
|
|
||||||
options.LoginPath = "/login";
|
|
||||||
options.LogoutPath = "/auth/logout";
|
|
||||||
options.ExpireTimeSpan = TimeSpan.FromDays(30);
|
|
||||||
options.SlidingExpiration = true;
|
|
||||||
});
|
|
||||||
builder.Services.AddAuthorization();
|
|
||||||
builder.Services.AddCascadingAuthenticationState();
|
|
||||||
builder.Services.AddHttpContextAccessor();
|
|
||||||
builder.Services.AddScoped<AuthService>();
|
|
||||||
|
|
||||||
// Add services to the container.
|
|
||||||
builder.Services.AddRazorComponents()
|
|
||||||
.AddInteractiveServerComponents();
|
|
||||||
builder.Services.AddMudServices();
|
|
||||||
builder.Services.AddHttpClient<HolidayService>();
|
|
||||||
|
|
||||||
var dbPath = Environment.GetEnvironmentVariable("TIMETRACKER_DB_PATH")
|
|
||||||
?? Path.Combine(builder.Environment.ContentRootPath, "timetracker.db");
|
|
||||||
builder.Services.AddDbContextFactory<TimetrackerDbContext>(options =>
|
|
||||||
options.UseSqlite($"Data Source={dbPath}"));
|
|
||||||
builder.Services.AddScoped<TimetrackerService>();
|
|
||||||
|
|
||||||
var app = builder.Build();
|
|
||||||
|
|
||||||
using (var scope = app.Services.CreateScope())
|
|
||||||
{
|
|
||||||
var factory = scope.ServiceProvider.GetRequiredService<IDbContextFactory<TimetrackerDbContext>>();
|
|
||||||
await using var db = await factory.CreateDbContextAsync();
|
|
||||||
await db.Database.MigrateAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
|
||||||
if (!app.Environment.IsDevelopment())
|
|
||||||
{
|
|
||||||
app.UseExceptionHandler("/Error", createScopeForErrors: true);
|
|
||||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
|
||||||
app.UseHsts();
|
|
||||||
}
|
|
||||||
app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true);
|
|
||||||
if (app.Configuration.GetValue("EnableHttpsRedirect", !app.Environment.IsDevelopment()))
|
|
||||||
{
|
|
||||||
app.UseHttpsRedirection();
|
|
||||||
}
|
|
||||||
|
|
||||||
app.UseAuthentication();
|
|
||||||
app.UseAuthorization();
|
|
||||||
|
|
||||||
app.UseAntiforgery();
|
|
||||||
|
|
||||||
app.MapStaticAssets();
|
|
||||||
app.MapRazorComponents<App>()
|
|
||||||
.AddInteractiveServerRenderMode();
|
|
||||||
|
|
||||||
// ── Auth-Endpoints ────────────────────────────────────────────────────────────
|
|
||||||
app.MapPost("/auth/login", async (HttpContext ctx, AuthService authService) =>
|
|
||||||
{
|
|
||||||
var form = await ctx.Request.ReadFormAsync();
|
|
||||||
var username = form["username"].ToString();
|
|
||||||
var password = form["password"].ToString();
|
|
||||||
var user = await authService.LoginAsync(username, password);
|
|
||||||
if (user == null)
|
|
||||||
return Results.Redirect("/login?error=invalid");
|
|
||||||
|
|
||||||
var claims = new[] {
|
|
||||||
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
|
|
||||||
new Claim(ClaimTypes.Name, user.Username)
|
|
||||||
};
|
|
||||||
var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
|
|
||||||
await ctx.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
|
|
||||||
new ClaimsPrincipal(identity),
|
|
||||||
new AuthenticationProperties { IsPersistent = true });
|
|
||||||
return Results.Redirect("/");
|
|
||||||
}).DisableAntiforgery();
|
|
||||||
|
|
||||||
app.MapPost("/auth/register", async (HttpContext ctx, AuthService authService) =>
|
|
||||||
{
|
|
||||||
var form = await ctx.Request.ReadFormAsync();
|
|
||||||
var username = form["username"].ToString();
|
|
||||||
var password = form["password"].ToString();
|
|
||||||
var (user, error) = await authService.RegisterAsync(username, password);
|
|
||||||
if (user == null)
|
|
||||||
return Results.Redirect($"/login?tab=register&error={Uri.EscapeDataString(error!)}");
|
|
||||||
|
|
||||||
var claims = new[] {
|
|
||||||
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
|
|
||||||
new Claim(ClaimTypes.Name, user.Username)
|
|
||||||
};
|
|
||||||
var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
|
|
||||||
await ctx.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
|
|
||||||
new ClaimsPrincipal(identity),
|
|
||||||
new AuthenticationProperties { IsPersistent = true });
|
|
||||||
return Results.Redirect("/");
|
|
||||||
}).DisableAntiforgery();
|
|
||||||
|
|
||||||
app.MapGet("/auth/logout", async (HttpContext ctx) =>
|
|
||||||
{
|
|
||||||
await ctx.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
|
||||||
return Results.Redirect("/login");
|
|
||||||
});
|
|
||||||
|
|
||||||
app.Run();
|
|
||||||
Binary file not shown.
BIN
Binary file not shown.
-68
@@ -1,68 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<configuration>
|
|
||||||
<startup>
|
|
||||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
|
|
||||||
</startup>
|
|
||||||
<runtime>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="Microsoft.Build" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-15.1.0.0" newVersion="15.1.0.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="Microsoft.Build.Framework" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-15.1.0.0" newVersion="15.1.0.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="Microsoft.Build.Utilities.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-15.1.0.0" newVersion="15.1.0.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="Microsoft.Build.Tasks.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-15.1.0.0" newVersion="15.1.0.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="Microsoft.IO.Redist" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-6.1.0.0" newVersion="6.1.0.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-4.0.4.0" newVersion="4.0.4.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-6.0.1.0" newVersion="6.0.1.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-4.2.1.0" newVersion="4.2.1.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
</runtime>
|
|
||||||
</configuration>
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-171
@@ -1,171 +0,0 @@
|
|||||||
{
|
|
||||||
"runtimeTarget": {
|
|
||||||
"name": ".NETCoreApp,Version=v8.0",
|
|
||||||
"signature": ""
|
|
||||||
},
|
|
||||||
"compilationOptions": {},
|
|
||||||
"targets": {
|
|
||||||
".NETCoreApp,Version=v8.0": {
|
|
||||||
"Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost/5.0.0-2.25567.12": {
|
|
||||||
"dependencies": {
|
|
||||||
"Microsoft.Build.Locator": "1.10.2",
|
|
||||||
"Newtonsoft.Json": "13.0.3",
|
|
||||||
"System.Collections.Immutable": "9.0.0",
|
|
||||||
"System.CommandLine": "2.0.0-rtm.25509.106"
|
|
||||||
},
|
|
||||||
"runtime": {
|
|
||||||
"Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.dll": {}
|
|
||||||
},
|
|
||||||
"resources": {
|
|
||||||
"cs/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
|
||||||
"locale": "cs"
|
|
||||||
},
|
|
||||||
"de/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
|
||||||
"locale": "de"
|
|
||||||
},
|
|
||||||
"es/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
|
||||||
"locale": "es"
|
|
||||||
},
|
|
||||||
"fr/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
|
||||||
"locale": "fr"
|
|
||||||
},
|
|
||||||
"it/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
|
||||||
"locale": "it"
|
|
||||||
},
|
|
||||||
"ja/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
|
||||||
"locale": "ja"
|
|
||||||
},
|
|
||||||
"ko/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
|
||||||
"locale": "ko"
|
|
||||||
},
|
|
||||||
"pl/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
|
||||||
"locale": "pl"
|
|
||||||
},
|
|
||||||
"pt-BR/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
|
||||||
"locale": "pt-BR"
|
|
||||||
},
|
|
||||||
"ru/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
|
||||||
"locale": "ru"
|
|
||||||
},
|
|
||||||
"tr/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
|
||||||
"locale": "tr"
|
|
||||||
},
|
|
||||||
"zh-Hans/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
|
||||||
"locale": "zh-Hans"
|
|
||||||
},
|
|
||||||
"zh-Hant/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
|
||||||
"locale": "zh-Hant"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Microsoft.Build.Locator/1.10.2": {
|
|
||||||
"runtime": {
|
|
||||||
"lib/net8.0/Microsoft.Build.Locator.dll": {
|
|
||||||
"assemblyVersion": "1.0.0.0",
|
|
||||||
"fileVersion": "1.10.2.26959"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Newtonsoft.Json/13.0.3": {
|
|
||||||
"runtime": {
|
|
||||||
"lib/net6.0/Newtonsoft.Json.dll": {
|
|
||||||
"assemblyVersion": "13.0.0.0",
|
|
||||||
"fileVersion": "13.0.3.27908"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"System.Collections.Immutable/9.0.0": {
|
|
||||||
"runtime": {
|
|
||||||
"lib/net8.0/System.Collections.Immutable.dll": {
|
|
||||||
"assemblyVersion": "9.0.0.0",
|
|
||||||
"fileVersion": "9.0.24.52809"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"System.CommandLine/2.0.0-rtm.25509.106": {
|
|
||||||
"runtime": {
|
|
||||||
"lib/net8.0/System.CommandLine.dll": {
|
|
||||||
"assemblyVersion": "2.0.0.0",
|
|
||||||
"fileVersion": "2.0.25.51006"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"resources": {
|
|
||||||
"lib/net8.0/cs/System.CommandLine.resources.dll": {
|
|
||||||
"locale": "cs"
|
|
||||||
},
|
|
||||||
"lib/net8.0/de/System.CommandLine.resources.dll": {
|
|
||||||
"locale": "de"
|
|
||||||
},
|
|
||||||
"lib/net8.0/es/System.CommandLine.resources.dll": {
|
|
||||||
"locale": "es"
|
|
||||||
},
|
|
||||||
"lib/net8.0/fr/System.CommandLine.resources.dll": {
|
|
||||||
"locale": "fr"
|
|
||||||
},
|
|
||||||
"lib/net8.0/it/System.CommandLine.resources.dll": {
|
|
||||||
"locale": "it"
|
|
||||||
},
|
|
||||||
"lib/net8.0/ja/System.CommandLine.resources.dll": {
|
|
||||||
"locale": "ja"
|
|
||||||
},
|
|
||||||
"lib/net8.0/ko/System.CommandLine.resources.dll": {
|
|
||||||
"locale": "ko"
|
|
||||||
},
|
|
||||||
"lib/net8.0/pl/System.CommandLine.resources.dll": {
|
|
||||||
"locale": "pl"
|
|
||||||
},
|
|
||||||
"lib/net8.0/pt-BR/System.CommandLine.resources.dll": {
|
|
||||||
"locale": "pt-BR"
|
|
||||||
},
|
|
||||||
"lib/net8.0/ru/System.CommandLine.resources.dll": {
|
|
||||||
"locale": "ru"
|
|
||||||
},
|
|
||||||
"lib/net8.0/tr/System.CommandLine.resources.dll": {
|
|
||||||
"locale": "tr"
|
|
||||||
},
|
|
||||||
"lib/net8.0/zh-Hans/System.CommandLine.resources.dll": {
|
|
||||||
"locale": "zh-Hans"
|
|
||||||
},
|
|
||||||
"lib/net8.0/zh-Hant/System.CommandLine.resources.dll": {
|
|
||||||
"locale": "zh-Hant"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"libraries": {
|
|
||||||
"Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost/5.0.0-2.25567.12": {
|
|
||||||
"type": "project",
|
|
||||||
"serviceable": false,
|
|
||||||
"sha512": ""
|
|
||||||
},
|
|
||||||
"Microsoft.Build.Locator/1.10.2": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-F+nLS7IpgtslyxNvtD6Jalnf5WU08lu8yfJBNQl3cbEF3AMUphs4t7nPuRYaaU8QZyGrqtVi7i73LhAe/yHx7A==",
|
|
||||||
"path": "microsoft.build.locator/1.10.2",
|
|
||||||
"hashPath": "microsoft.build.locator.1.10.2.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"Newtonsoft.Json/13.0.3": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==",
|
|
||||||
"path": "newtonsoft.json/13.0.3",
|
|
||||||
"hashPath": "newtonsoft.json.13.0.3.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"System.Collections.Immutable/9.0.0": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-QhkXUl2gNrQtvPmtBTQHb0YsUrDiDQ2QS09YbtTTiSjGcf7NBqtYbrG/BE06zcBPCKEwQGzIv13IVdXNOSub2w==",
|
|
||||||
"path": "system.collections.immutable/9.0.0",
|
|
||||||
"hashPath": "system.collections.immutable.9.0.0.nupkg.sha512"
|
|
||||||
},
|
|
||||||
"System.CommandLine/2.0.0-rtm.25509.106": {
|
|
||||||
"type": "package",
|
|
||||||
"serviceable": true,
|
|
||||||
"sha512": "sha512-IdCQOFNHQfK0hu3tzWOHFJLMaiEOR/4OynmOh+IfukrTIsCR4TTDm7lpuXQyMZ0eRfIyUcz06gHGJNlILAq/6A==",
|
|
||||||
"path": "system.commandline/2.0.0-rtm.25509.106",
|
|
||||||
"hashPath": "system.commandline.2.0.0-rtm.25509.106.nupkg.sha512"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BIN
Binary file not shown.
-14
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"runtimeOptions": {
|
|
||||||
"tfm": "net8.0",
|
|
||||||
"framework": {
|
|
||||||
"name": "Microsoft.NETCore.App",
|
|
||||||
"version": "8.0.0"
|
|
||||||
},
|
|
||||||
"rollForward": "Major",
|
|
||||||
"configProperties": {
|
|
||||||
"System.Reflection.Metadata.MetadataUpdater.IsSupported": false,
|
|
||||||
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft.AspNetCore": "Warning"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft.AspNetCore": "Warning"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowedHosts": "*"
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user