Compare commits
87 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5fcc42a99f | |||
| 9204fed54c | |||
| 406d0f5652 | |||
| 9cd651bdfe | |||
| 96336fd637 | |||
| e7d1b4b524 | |||
| a4d7269f8f | |||
| c7d741d15b | |||
| 6d2a6c5925 | |||
| 9ccb929553 | |||
| 5e086c0598 | |||
| a7c86289b3 | |||
| b2e851d765 | |||
| 1a1d7dec7c | |||
| 103da6abe8 | |||
| 5f2fdbac87 | |||
| e0ceb7d314 | |||
| 8df80eba3b | |||
| 77875110f0 | |||
| ddbc6affd1 | |||
| cd41eea0d9 | |||
| d15ecd926c | |||
| 78774abffd | |||
| a8cc182265 | |||
| 65e03c2586 | |||
| 45c4379d53 | |||
| 55d65f4841 | |||
| 3f4feb9dc9 | |||
| 45479d9df7 | |||
| 1d077fe1cc | |||
| 2046939d8a | |||
| 02d2a26a82 | |||
| c00fb3234c | |||
| 6922303e52 | |||
| 3ffad3abbe | |||
| 68afe22526 | |||
| 28fe48c3f0 | |||
| 8cd0dc6c81 | |||
| 8c4a3def23 | |||
| ef41d46e50 | |||
| f8eba6b8dd | |||
| 99581df6f7 | |||
| 6991af3daa | |||
| 04ca70dc67 | |||
| cd159509a0 | |||
| ea7604a05f | |||
| 622a751c40 | |||
| 0f3da6952b | |||
| 59442d5203 | |||
| 94e3104773 | |||
| dcbff4e30d | |||
| 7af23518e5 | |||
| 226cc38bf7 | |||
| 8e615c15f0 | |||
| 352a7dbfde | |||
| 2e9ea45bd9 | |||
| e7f8e8c331 | |||
| 9fab942181 | |||
| b316a882c5 | |||
| 594541a103 | |||
| ee7bcc1eae | |||
| 4fe354add0 | |||
| 44cbfc9c55 | |||
| c6355d47df | |||
| 97a92269ad | |||
| 66468a1f8b | |||
| e48e8b6394 | |||
| 5f39417109 | |||
| 76e8e8daa6 | |||
| 6db2bca50b | |||
| 46491dd987 | |||
| 8edf749e23 | |||
| 3cc4fd8240 | |||
| d0f91fd0e1 | |||
| f1a68296ec | |||
| c5a3ba2b40 | |||
| 67b559e6d7 | |||
| 3c10721c4e | |||
| eec7f40e72 | |||
| 899a36a49c | |||
| 8e607ee180 | |||
| 87e6132f34 | |||
| dd845f4be6 | |||
| 6ca8fe7bdc | |||
| 56bcd712f1 | |||
| 4e3eca0650 | |||
| 2160c9abbc |
@@ -24,13 +24,6 @@ jobs:
|
||||
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||
echo "REPO_LC=${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV
|
||||
|
||||
- name: Login to own image registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: gitea.penry.de
|
||||
username: ${{ secrets.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Setup .NET10
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
@@ -42,8 +35,16 @@ jobs:
|
||||
-t gitea.penry.de/${{ env.REPO_LC }}:${{ env.VERSION }} \
|
||||
-t gitea.penry.de/${{ env.REPO_LC }}:latest \
|
||||
--label "org.opencontainers.image.source=https://gitea.penry.de/${{ github.repository }}" \
|
||||
--build-arg VERSION=${{ env.VERSION }} \
|
||||
.
|
||||
|
||||
- name: Login to own image registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: gitea.penry.de
|
||||
username: ${{ secrets.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Push Images
|
||||
run: |
|
||||
docker push gitea.penry.de/${{ env.REPO_LC }}:${{ env.VERSION }}
|
||||
|
||||
@@ -3,7 +3,7 @@ name: Build Docker Linux ARM64
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
#- main
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build-docker-linux-arm64:
|
||||
@@ -14,15 +14,66 @@ jobs:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Get Repository Name
|
||||
id: get_repo
|
||||
run: |
|
||||
REPO_LC="${GITHUB_REPOSITORY,,}"
|
||||
echo "REPO_LC=$REPO_LC" >> $GITHUB_ENV
|
||||
echo "Repo: $REPO_LC"
|
||||
|
||||
- name: Build version
|
||||
shell: bash
|
||||
run: |
|
||||
LAST_TAG=$(git describe --tags --abbrev=0)
|
||||
|
||||
if [[ -z "${LAST_TAG:-}" ]]; then
|
||||
echo "No tag found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
COMMIT_COUNT=$(git rev-list $LAST_TAG..HEAD --count)
|
||||
|
||||
if [[ "$LAST_TAG" == *-* ]]; then
|
||||
TEMP_LAST_TAG="${LAST_TAG%-*}"
|
||||
VERSION="${TEMP_LAST_TAG}-nightly.${COMMIT_COUNT}"
|
||||
else
|
||||
VERSION="${LAST_TAG}-nightly.${COMMIT_COUNT}"
|
||||
fi
|
||||
|
||||
echo "LAST_TAG=$LAST_TAG" >> "$GITHUB_ENV"
|
||||
echo "COMMIT_COUNT=$COMMIT_COUNT" >> "$GITHUB_ENV"
|
||||
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
|
||||
|
||||
echo "Last tag: $LAST_TAG"
|
||||
echo "Commit count: $COMMIT_COUNT"
|
||||
echo "Final version: $VERSION"
|
||||
|
||||
- name: Build Linux ARM64 Docker Image
|
||||
run: docker build -t couchlog-linux-arm64 .
|
||||
run: |
|
||||
docker build \
|
||||
-t gitea.penry.de/${{ env.REPO_LC }}:nightly \
|
||||
--build-arg VERSION=${{ env.VERSION }} \
|
||||
.
|
||||
|
||||
- name: Login to own image registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: gitea.penry.de
|
||||
username: ${{ secrets.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Push Images
|
||||
run: |
|
||||
docker push gitea.penry.de/${{ env.REPO_LC }}:nightly
|
||||
|
||||
- name: Save Docker Image to Tar
|
||||
run: docker save -o CouchLog-Linux-ARM64-Docker-Image.tar couchlog-linux-arm64
|
||||
run: docker save -o CouchLog-Linux-ARM64-Docker-Image.tar gitea.penry.de/${{ env.REPO_LC }}:nightly
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
@@ -30,4 +81,4 @@ jobs:
|
||||
name: CouchLog-Linux-ARM64-Docker-Image
|
||||
path: CouchLog-Linux-ARM64-Docker-Image.tar
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
retention-days: 5
|
||||
@@ -2,5 +2,7 @@
|
||||
bin
|
||||
Debug
|
||||
/CouchLog/Data/CouchLog.db
|
||||
/CouchLog/Data/CouchLog.db-shm
|
||||
/CouchLog/Data/CouchLog.db-wal
|
||||
#Migrations
|
||||
obj
|
||||
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"terminal.explorerKind": "integrated"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
[*.cs]
|
||||
|
||||
# IDE0130: Namespace does not match folder structure
|
||||
dotnet_diagnostic.IDE0130.severity = none
|
||||
@@ -54,7 +54,7 @@
|
||||
private HttpContext HttpContext { get; set; } = default!;
|
||||
|
||||
[SupplyParameterFromForm]
|
||||
private InputModel Input { get; set; } = new();
|
||||
private InputModel Input { get; set; } = null!;
|
||||
|
||||
[SupplyParameterFromQuery]
|
||||
private string? RemoteError { get; set; }
|
||||
@@ -94,6 +94,8 @@
|
||||
// the login page if we get here some other way.
|
||||
RedirectManager.RedirectTo("Account/Login");
|
||||
}
|
||||
|
||||
Input ??= new InputModel();
|
||||
}
|
||||
|
||||
private async Task OnLoginCallbackAsync()
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
@code {
|
||||
[SupplyParameterFromForm]
|
||||
private InputModel Input { get; set; } = new();
|
||||
private InputModel Input { get; set; } = null!;
|
||||
|
||||
private async Task OnValidSubmitAsync()
|
||||
{
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
@page "/Account/Login"
|
||||
@layout Layout.IdentityLayout
|
||||
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@using Microsoft.AspNetCore.Authentication
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
@using CouchLog.Data
|
||||
@using MudBlazor
|
||||
|
||||
@inject SignInManager<ApplicationUser> SignInManager
|
||||
@inject ILogger<Login> Logger
|
||||
@@ -12,57 +14,59 @@
|
||||
|
||||
<PageTitle>Log in</PageTitle>
|
||||
|
||||
<h1>Log in</h1>
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<section>
|
||||
<MudGrid Justify="Justify.Center" Class="align-center">
|
||||
@* Linke Spalte: Login-Formular *@
|
||||
<MudItem xs="12" md="7">
|
||||
<MudPaper Elevation="3" Class="pa-6">
|
||||
<StatusMessage Message="@errorMessage" />
|
||||
|
||||
<EditForm Model="Input" method="post" OnValidSubmit="LoginUser" FormName="login">
|
||||
<DataAnnotationsValidator />
|
||||
<h2>Use a local account to log in.</h2>
|
||||
<hr />
|
||||
|
||||
<MudText Typo="Typo.h5" GutterBottom="true" Align="Align.Center">Login</MudText>
|
||||
<MudDivider Class="mb-6" />
|
||||
|
||||
<ValidationSummary class="text-danger" role="alert" />
|
||||
<div class="form-floating mb-3">
|
||||
<InputText @bind-Value="Input.Username" id="Input.Username" class="form-control" autocomplete="username" aria-required="true" placeholder="Username" />
|
||||
<label for="Input.Username" class="form-label">Username</label>
|
||||
<ValidationMessage For="() => Input.Username" class="text-danger" />
|
||||
|
||||
@* MudTextFields zwingend mit Name-Attribut für SSR *@
|
||||
<MudTextField @bind-Value="Input.Username"
|
||||
For="@(() => Input.Username)"
|
||||
name="Input.Username"
|
||||
Label="Username"
|
||||
Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense"
|
||||
ShrinkLabel="true"
|
||||
Class="mb-4" />
|
||||
|
||||
<MudTextField @bind-Value="Input.Password"
|
||||
For="@(() => Input.Password)"
|
||||
name="Input.Password"
|
||||
Label="Password"
|
||||
InputType="InputType.Password"
|
||||
Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense"
|
||||
ShrinkLabel="true"
|
||||
Class="mb-4" />
|
||||
|
||||
@* Standard-Checkbox mit MudBlazor-Typografie *@
|
||||
<div class="d-flex align-center mb-6">
|
||||
<InputCheckbox @bind-Value="Input.RememberMe" id="Input.RememberMe" style="width: 1.2rem; height: 1.2rem; accent-color: var(--mud-palette-primary);" />
|
||||
<label for="Input.RememberMe" class="ml-2 mud-typography mud-typography-body1">Remember me</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<InputText type="password" @bind-Value="Input.Password" id="Input.Password" class="form-control" autocomplete="current-password" aria-required="true" placeholder="Password" />
|
||||
<label for="Input.Password" class="form-label">Password</label>
|
||||
<ValidationMessage For="() => Input.Password" class="text-danger" />
|
||||
</div>
|
||||
<div class="checkbox mb-3">
|
||||
<label class="form-label">
|
||||
<InputCheckbox @bind-Value="Input.RememberMe" class="darker-border-checkbox form-check-input" />
|
||||
Remember me
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit" class="w-100 btn btn-lg btn-primary">Log in</button>
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
<a href="Account/ForgotPassword">Forgot your password?</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="@(NavigationManager.GetUriWithQueryParameters("Account/Register", new Dictionary<string, object?> { ["ReturnUrl"] = ReturnUrl }))">Register as a new user</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="Account/ResendEmailConfirmation">Resend email confirmation</a>
|
||||
</p>
|
||||
|
||||
<MudButton ButtonType="ButtonType.Submit" Variant="Variant.Filled" Color="Color.Primary" Size="Size.Large" FullWidth="true" Class="mb-4">
|
||||
Log in
|
||||
</MudButton>
|
||||
|
||||
<div class="d-flex flex-column gap-2 mt-4">
|
||||
<MudLink Href="Account/ForgotPassword" Typo="Typo.body2">Forgot your password?</MudLink>
|
||||
<MudLink Href="@(NavigationManager.GetUriWithQueryParameters("Account/Register", new Dictionary<string, object?> { ["ReturnUrl"] = ReturnUrl }))" Typo="Typo.body2">Register as a new user</MudLink>
|
||||
<MudLink Href="Account/ResendEmailConfirmation" Typo="Typo.body2">Resend email confirmation</MudLink>
|
||||
</div>
|
||||
</EditForm>
|
||||
</section>
|
||||
</div>
|
||||
<div class="col-lg-4 col-lg-offset-2">
|
||||
<section>
|
||||
<h3>Use another service to log in.</h3>
|
||||
<hr />
|
||||
<ExternalLoginPicker />
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
|
||||
@code {
|
||||
private string? errorMessage;
|
||||
@@ -71,7 +75,7 @@
|
||||
private HttpContext HttpContext { get; set; } = default!;
|
||||
|
||||
[SupplyParameterFromForm]
|
||||
private InputModel Input { get; set; } = new();
|
||||
private InputModel Input { get; set; } = null!;
|
||||
|
||||
[SupplyParameterFromQuery]
|
||||
private string? ReturnUrl { get; set; }
|
||||
@@ -83,6 +87,8 @@
|
||||
// Clear the existing external cookie to ensure a clean login process
|
||||
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
|
||||
}
|
||||
|
||||
Input ??= new InputModel();
|
||||
}
|
||||
|
||||
public async Task LoginUser()
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
private ApplicationUser user = default!;
|
||||
|
||||
[SupplyParameterFromForm]
|
||||
private InputModel Input { get; set; } = new();
|
||||
private InputModel Input { get; set; } = null!;
|
||||
|
||||
[SupplyParameterFromQuery]
|
||||
private string? ReturnUrl { get; set; }
|
||||
@@ -62,6 +62,8 @@
|
||||
// Ensure the user has gone through the username & password screen first
|
||||
user = await SignInManager.GetTwoFactorAuthenticationUserAsync() ??
|
||||
throw new InvalidOperationException("Unable to load two-factor authentication user.");
|
||||
|
||||
Input ??= new InputModel();
|
||||
}
|
||||
|
||||
private async Task OnValidSubmitAsync()
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
private ApplicationUser user = default!;
|
||||
|
||||
[SupplyParameterFromForm]
|
||||
private InputModel Input { get; set; } = new();
|
||||
private InputModel Input { get; set; } = null!;
|
||||
|
||||
[SupplyParameterFromQuery]
|
||||
private string? ReturnUrl { get; set; }
|
||||
@@ -48,6 +48,8 @@
|
||||
// Ensure the user has gone through the username & password screen first
|
||||
user = await SignInManager.GetTwoFactorAuthenticationUserAsync() ??
|
||||
throw new InvalidOperationException("Unable to load two-factor authentication user.");
|
||||
|
||||
Input ??= new InputModel();
|
||||
}
|
||||
|
||||
private async Task OnValidSubmitAsync()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@page "/Account/Manage/ChangePassword"
|
||||
@page "/Account/ChangePassword"
|
||||
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
@@ -9,67 +9,81 @@
|
||||
@inject IdentityUserAccessor UserAccessor
|
||||
@inject IdentityRedirectManager RedirectManager
|
||||
@inject ILogger<ChangePassword> Logger
|
||||
@inject ISnackbar Snackbar
|
||||
|
||||
<PageTitle>Change password</PageTitle>
|
||||
|
||||
<h3>Change password</h3>
|
||||
<StatusMessage Message="@message" />
|
||||
<div class="row">
|
||||
<div class="col-xl-6">
|
||||
<MudText Typo="Typo.h6">Change password</MudText>
|
||||
|
||||
<EditForm Model="Input" FormName="change-password" OnValidSubmit="OnValidSubmitAsync" method="post">
|
||||
<DataAnnotationsValidator />
|
||||
<ValidationSummary class="text-danger" role="alert" />
|
||||
<div class="form-floating mb-3">
|
||||
<InputText type="password" @bind-Value="Input.OldPassword" id="Input.OldPassword" class="form-control" autocomplete="current-password" aria-required="true" placeholder="Enter the old password" />
|
||||
<label for="Input.OldPassword" class="form-label">Old password</label>
|
||||
<ValidationMessage For="() => Input.OldPassword" class="text-danger" />
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<InputText type="password" @bind-Value="Input.NewPassword" id="Input.NewPassword" class="form-control" autocomplete="new-password" aria-required="true" placeholder="Enter the new password" />
|
||||
<label for="Input.NewPassword" class="form-label">New password</label>
|
||||
<ValidationMessage For="() => Input.NewPassword" class="text-danger" />
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<InputText type="password" @bind-Value="Input.ConfirmPassword" id="Input.ConfirmPassword" class="form-control" autocomplete="new-password" aria-required="true" placeholder="Enter the new password" />
|
||||
<label for="Input.ConfirmPassword" class="form-label">Confirm password</label>
|
||||
<ValidationMessage For="() => Input.ConfirmPassword" class="text-danger" />
|
||||
</div>
|
||||
<button type="submit" class="w-100 btn btn-lg btn-primary">Update password</button>
|
||||
|
||||
<MudTextField
|
||||
T="string"
|
||||
name="Input.OldPassword"
|
||||
Label="OldPassword"
|
||||
@bind-Value="Input.OldPassword"
|
||||
For="@(() => Input.OldPassword)"
|
||||
InputType="InputType.Password"
|
||||
Required="true"
|
||||
Variant="Variant.Outlined"
|
||||
ShrinkLabel="true"/>
|
||||
|
||||
<MudTextField
|
||||
T="string"
|
||||
name="Input.NewPassword"
|
||||
Label="New password"
|
||||
@bind-Value="Input.NewPassword"
|
||||
For="@(() => Input.NewPassword)"
|
||||
InputType="InputType.Password"
|
||||
Required="true"
|
||||
Variant="Variant.Outlined"
|
||||
ShrinkLabel="true"/>
|
||||
|
||||
<MudTextField
|
||||
T="string"
|
||||
name="Input.ConfirmPassword"
|
||||
Label="Confirm password"
|
||||
@bind-Value="Input.ConfirmPassword"
|
||||
For="@(() => Input.ConfirmPassword)"
|
||||
InputType="InputType.Password"
|
||||
Required="true"
|
||||
Variant="Variant.Outlined"
|
||||
ShrinkLabel="true"/>
|
||||
|
||||
<MudButton ButtonType="ButtonType.Submit" Variant="Variant.Filled" Color="Color.Primary">Change password</MudButton>
|
||||
</EditForm>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private string? message;
|
||||
private ApplicationUser user = default!;
|
||||
private bool hasPassword;
|
||||
private ApplicationUser _user = null!;
|
||||
private bool _hasPassword;
|
||||
|
||||
[CascadingParameter]
|
||||
private HttpContext HttpContext { get; set; } = default!;
|
||||
private HttpContext HttpContext { get; set; } = null!;
|
||||
|
||||
[SupplyParameterFromForm]
|
||||
private InputModel Input { get; set; } = new();
|
||||
private InputModel Input { get; set; } = null!;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
user = await UserAccessor.GetRequiredUserAsync(HttpContext);
|
||||
hasPassword = await UserManager.HasPasswordAsync(user);
|
||||
if (!hasPassword)
|
||||
_user = await UserAccessor.GetRequiredUserAsync(HttpContext);
|
||||
_hasPassword = await UserManager.HasPasswordAsync(_user);
|
||||
if (!_hasPassword)
|
||||
{
|
||||
RedirectManager.RedirectTo("Account/Manage/SetPassword");
|
||||
}
|
||||
Input ??= new InputModel();
|
||||
}
|
||||
|
||||
private async Task OnValidSubmitAsync()
|
||||
{
|
||||
var changePasswordResult = await UserManager.ChangePasswordAsync(user, Input.OldPassword, Input.NewPassword);
|
||||
var changePasswordResult = await UserManager.ChangePasswordAsync(_user, Input.OldPassword, Input.NewPassword);
|
||||
if (!changePasswordResult.Succeeded)
|
||||
{
|
||||
message = $"Error: {string.Join(",", changePasswordResult.Errors.Select(error => error.Description))}";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await SignInManager.RefreshSignInAsync(user);
|
||||
await SignInManager.RefreshSignInAsync(_user);
|
||||
Logger.LogInformation("User changed their password successfully.");
|
||||
|
||||
RedirectManager.RedirectToCurrentPageWithStatus("Your password has been changed", HttpContext);
|
||||
|
||||
@@ -47,13 +47,15 @@
|
||||
private HttpContext HttpContext { get; set; } = default!;
|
||||
|
||||
[SupplyParameterFromForm]
|
||||
private InputModel Input { get; set; } = new();
|
||||
private InputModel Input { get; set; } = null!;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
Input ??= new();
|
||||
user = await UserAccessor.GetRequiredUserAsync(HttpContext);
|
||||
requirePassword = await UserManager.HasPasswordAsync(user);
|
||||
|
||||
Input ??= new InputModel();
|
||||
}
|
||||
|
||||
private async Task OnValidSubmitAsync()
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
private HttpContext HttpContext { get; set; } = default!;
|
||||
|
||||
[SupplyParameterFromForm(FormName = "change-email")]
|
||||
private InputModel Input { get; set; } = new();
|
||||
private InputModel Input { get; set; } = null!;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
@@ -72,6 +72,7 @@
|
||||
isEmailConfirmed = await UserManager.IsEmailConfirmedAsync(user);
|
||||
|
||||
Input.NewEmail ??= email;
|
||||
Input ??= new InputModel();
|
||||
}
|
||||
|
||||
private async Task OnValidSubmitAsync()
|
||||
|
||||
@@ -79,7 +79,7 @@ else
|
||||
private HttpContext HttpContext { get; set; } = default!;
|
||||
|
||||
[SupplyParameterFromForm]
|
||||
private InputModel Input { get; set; } = new();
|
||||
private InputModel Input { get; set; } = null!;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
|
||||
@@ -11,27 +11,14 @@
|
||||
|
||||
<PageTitle>Profile</PageTitle>
|
||||
|
||||
<h3>Profile</h3>
|
||||
<MudText Typo="Typo.h6">Profile</MudText>
|
||||
<StatusMessage />
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xl-6">
|
||||
<EditForm Model="Input" FormName="profile" OnValidSubmit="OnValidSubmitAsync" method="post">
|
||||
<DataAnnotationsValidator />
|
||||
<ValidationSummary class="text-danger" role="alert" />
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" value="@username" id="username" class="form-control" placeholder="Choose your username." disabled />
|
||||
<label for="username" class="form-label">Username</label>
|
||||
</div>
|
||||
<!--<div class="form-floating mb-3">
|
||||
<InputText @bind-Value="Input.PhoneNumber" id="Input.PhoneNumber" class="form-control" placeholder="Enter your phone number" />
|
||||
<label for="Input.PhoneNumber" class="form-label">Phone number</label>
|
||||
<ValidationMessage For="() => Input.PhoneNumber" class="text-danger" />
|
||||
</div>
|
||||
<button type="submit" class="w-100 btn btn-lg btn-primary">Save</button>-->
|
||||
</EditForm>
|
||||
</div>
|
||||
</div>
|
||||
<MudContainer Class="pa-0 ma-0">
|
||||
<MudTextField Value="@username" Variant="Variant.Outlined" Label="Username"/>
|
||||
</MudContainer>
|
||||
|
||||
|
||||
|
||||
@code {
|
||||
private ApplicationUser user = default!;
|
||||
@@ -42,7 +29,7 @@
|
||||
private HttpContext HttpContext { get; set; } = default!;
|
||||
|
||||
[SupplyParameterFromForm]
|
||||
private InputModel Input { get; set; } = new();
|
||||
private InputModel Input { get; set; } = null!;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
private HttpContext HttpContext { get; set; } = default!;
|
||||
|
||||
[SupplyParameterFromForm]
|
||||
private InputModel Input { get; set; } = new();
|
||||
private InputModel Input { get; set; } = null!;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@page "/Account/Register"
|
||||
@layout Layout.IdentityLayout
|
||||
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@using System.Text
|
||||
@@ -10,10 +11,10 @@
|
||||
@inject UserManager<ApplicationUser> UserManager
|
||||
@inject IUserStore<ApplicationUser> UserStore
|
||||
@inject SignInManager<ApplicationUser> SignInManager
|
||||
@inject IEmailSender<ApplicationUser> EmailSender
|
||||
@inject ILogger<Register> Logger
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IdentityRedirectManager RedirectManager
|
||||
@inject ApplicationDbContext CouchLogDB
|
||||
|
||||
<PageTitle>Register</PageTitle>
|
||||
|
||||
@@ -28,9 +29,9 @@
|
||||
<hr />
|
||||
<ValidationSummary class="text-danger" role="alert" />
|
||||
<div class="form-floating mb-3">
|
||||
<InputText @bind-Value="Input.Email" id="Input.Email" class="form-control" autocomplete="username" aria-required="true" placeholder="name@example.com" />
|
||||
<label for="Input.Email">Email</label>
|
||||
<ValidationMessage For="() => Input.Email" class="text-danger" />
|
||||
<InputText @bind-Value="Input.Username" id="Input.Username" class="form-control" autocomplete="username" aria-required="true" placeholder="NewUsername" />
|
||||
<label for="Input.Username">Username</label>
|
||||
<ValidationMessage For="() => Input.Username" class="text-danger" />
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<InputText type="password" @bind-Value="Input.Password" id="Input.Password" class="form-control" autocomplete="new-password" aria-required="true" placeholder="password" />
|
||||
@@ -58,7 +59,7 @@
|
||||
private IEnumerable<IdentityError>? identityErrors;
|
||||
|
||||
[SupplyParameterFromForm]
|
||||
private InputModel Input { get; set; } = new();
|
||||
private InputModel Input { get; set; } = null!;
|
||||
|
||||
[SupplyParameterFromQuery]
|
||||
private string? ReturnUrl { get; set; }
|
||||
@@ -67,11 +68,19 @@
|
||||
|
||||
public async Task RegisterUser(EditContext editContext)
|
||||
{
|
||||
if(!CouchLogDB.AccountsSettings.First().IsRegistrationAllowed)
|
||||
{
|
||||
identityErrors = new[]
|
||||
{
|
||||
new IdentityError { Description = "Registration is deactivated" }
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
var user = CreateUser();
|
||||
|
||||
await UserStore.SetUserNameAsync(user, Input.Email, CancellationToken.None);
|
||||
var emailStore = GetEmailStore();
|
||||
await emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);
|
||||
await UserStore.SetUserNameAsync(user, Input.Username, CancellationToken.None);
|
||||
user.EmailConfirmed = true;
|
||||
var result = await UserManager.CreateAsync(user, Input.Password);
|
||||
|
||||
if (!result.Succeeded)
|
||||
@@ -80,23 +89,24 @@
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.LogInformation("User created a new account with password.");
|
||||
|
||||
var userId = await UserManager.GetUserIdAsync(user);
|
||||
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
|
||||
var callbackUrl = NavigationManager.GetUriWithQueryParameters(
|
||||
NavigationManager.ToAbsoluteUri("Account/ConfirmEmail").AbsoluteUri,
|
||||
new Dictionary<string, object?> { ["userId"] = userId, ["code"] = code, ["returnUrl"] = ReturnUrl });
|
||||
|
||||
await EmailSender.SendConfirmationLinkAsync(user, Input.Email, HtmlEncoder.Default.Encode(callbackUrl));
|
||||
|
||||
if (UserManager.Options.SignIn.RequireConfirmedAccount)
|
||||
if(CouchLogDB.CouchLogState.Count() == 0)
|
||||
{
|
||||
RedirectManager.RedirectTo(
|
||||
"Account/RegisterConfirmation",
|
||||
new() { ["email"] = Input.Email, ["returnUrl"] = ReturnUrl });
|
||||
await UserManager.AddToRoleAsync(user, "Admin");
|
||||
await CouchLogDB.CouchLogState.AddAsync(new CouchLogState
|
||||
{
|
||||
Id = 1,
|
||||
InitializationDate = DateTime.Now,
|
||||
IsInitialized = true
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
await UserManager.AddToRoleAsync(user, "User");
|
||||
}
|
||||
|
||||
await CouchLogDB.SaveChangesAsync();
|
||||
|
||||
Logger.LogInformation("User created a new account with password.");
|
||||
|
||||
await SignInManager.SignInAsync(user, isPersistent: false);
|
||||
RedirectManager.RedirectTo(ReturnUrl);
|
||||
@@ -127,9 +137,8 @@
|
||||
private sealed class InputModel
|
||||
{
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
[Display(Name = "Email")]
|
||||
public string Email { get; set; } = "";
|
||||
[Display(Name = "Username")]
|
||||
public string Username { get; set; } = "";
|
||||
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
private string? message;
|
||||
|
||||
[SupplyParameterFromForm]
|
||||
private InputModel Input { get; set; } = new();
|
||||
private InputModel Input { get; set; } = null!;
|
||||
|
||||
private async Task OnValidSubmitAsync()
|
||||
{
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
private IEnumerable<IdentityError>? identityErrors;
|
||||
|
||||
[SupplyParameterFromForm]
|
||||
private InputModel Input { get; set; } = new();
|
||||
private InputModel Input { get; set; } = null!;
|
||||
|
||||
[SupplyParameterFromQuery]
|
||||
private string? Code { get; set; }
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
@inherits LayoutComponentBase
|
||||
@layout CouchLog.Components.Layout.MainLayout
|
||||
|
||||
<h1>Manage your account</h1>
|
||||
<MudText Typo="Typo.h2">Manage your account</MudText>
|
||||
|
||||
<div>
|
||||
<h2>Change your account settings</h2>
|
||||
<MudContainer MaxWidth="MaxWidth.False" Class="pa-4">
|
||||
<MudText Typo="Typo.h4">Change your account settings</MudText>
|
||||
<hr/>
|
||||
<div class="row">
|
||||
<div class="col-lg-3">
|
||||
<MudGrid>
|
||||
<MudItem xs="12" md="3" lg="2">
|
||||
<ManageNavMenu/>
|
||||
</div>
|
||||
<div class="col-lg-9">
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" md="9" lg="10">
|
||||
@Body
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
@@ -3,33 +3,41 @@
|
||||
|
||||
@inject SignInManager<ApplicationUser> SignInManager
|
||||
|
||||
<ul class="nav nav-pills flex-column">
|
||||
<li class="nav-item">
|
||||
<NavLink class="nav-link" href="Account/Manage" Match="NavLinkMatch.All">Profile</NavLink>
|
||||
</li>
|
||||
<MudNavMenu>
|
||||
<MudNavLink Href="Account/Manage"
|
||||
Icon="@Icons.Material.Filled.ManageAccounts">
|
||||
Manage
|
||||
</MudNavLink>
|
||||
<!--
|
||||
<li class="nav-item">
|
||||
<NavLink class="nav-link" href="Account/Manage/Email">Email</NavLink>
|
||||
</li>
|
||||
<MudNavLink Href="Account/Manage/Email"
|
||||
Icon="@Icons.Material.Filled.Email">
|
||||
Email
|
||||
</MudNavLink>
|
||||
-->
|
||||
<li class="nav-item">
|
||||
<NavLink class="nav-link" href="Account/Manage/ChangePassword">Password</NavLink>
|
||||
</li>
|
||||
<MudNavLink Href="Account/ChangePassword"
|
||||
Icon="@Icons.Material.Filled.Password">
|
||||
Password
|
||||
</MudNavLink>
|
||||
@if (hasExternalLogins)
|
||||
{
|
||||
<li class="nav-item">
|
||||
<NavLink class="nav-link" href="Account/Manage/ExternalLogins">External logins</NavLink>
|
||||
</li>
|
||||
<MudNavLink Href="Account/Manage/ExternalLogins"
|
||||
Icon="@Icons.Material.Filled.Login">
|
||||
External logins
|
||||
</MudNavLink>
|
||||
}
|
||||
<!--
|
||||
<li class="nav-item">
|
||||
<NavLink class="nav-link" href="Account/Manage/TwoFactorAuthentication">Two-factor authentication</NavLink>
|
||||
</li>
|
||||
<MudNavLink Href="Account/Manage/TwoFactorAuthentication"
|
||||
Icon="@Icons.Material.Filled.FactCheck">
|
||||
Two-factor authentication
|
||||
</MudNavLink>
|
||||
-->
|
||||
<li class="nav-item">
|
||||
<NavLink class="nav-link" href="Account/Manage/PersonalData">Personal data</NavLink>
|
||||
</li>
|
||||
</ul>
|
||||
<!--
|
||||
<MudNavLink Href="Account/Manage/PersonalData"
|
||||
Icon="@Icons.Material.Filled.DataObject">
|
||||
Personal data
|
||||
</MudNavLink>
|
||||
-->
|
||||
</MudNavMenu>
|
||||
|
||||
@code {
|
||||
private bool hasExternalLogins;
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
@page "/AdminSettings/CouchLogSettings"
|
||||
@rendermode InteractiveServer
|
||||
|
||||
@using System.Reflection
|
||||
@using CouchLog.Data
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
|
||||
@inject ApplicationDbContext CouchLogDb
|
||||
|
||||
<MudText Typo="Typo.h3">CouchLog Settings</MudText>
|
||||
|
||||
<EditForm Model="_accountsSettings">
|
||||
<MudSwitch T="bool"
|
||||
Label="Is Registration allowed"
|
||||
Value="_accountsSettings.IsRegistrationAllowed"
|
||||
ValueChanged="OnRegistrationChanged"
|
||||
Color="Color.Primary" />
|
||||
</EditForm>
|
||||
|
||||
@*<MudText>Version: @_version</MudText>*@
|
||||
|
||||
@code {
|
||||
private AccountsSettings _accountsSettings = null!;
|
||||
//private readonly string _version = Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion?.Split('+')[0];
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_accountsSettings = await CouchLogDb.AccountsSettings.FirstAsync();
|
||||
}
|
||||
|
||||
private async Task OnRegistrationChanged(bool value)
|
||||
{
|
||||
_accountsSettings!.IsRegistrationAllowed = value;
|
||||
|
||||
CouchLogDb.AccountsSettings.Update(_accountsSettings);
|
||||
await CouchLogDb.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
@using CouchLog.Data
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
|
||||
@inject UserManager<ApplicationUser> UserManager
|
||||
@inject ISnackbar Snackbar
|
||||
|
||||
<MudDialog>
|
||||
<TitleContent>
|
||||
<MudText Typo="Typo.h6">Create New User</MudText>
|
||||
</TitleContent>
|
||||
|
||||
<DialogContent>
|
||||
<MudInput @bind-Value="@_newUsername"></MudInput>
|
||||
<MudSelect @bind-Value="_newUserRole">
|
||||
@foreach (var role in Roles)
|
||||
{
|
||||
<MudSelectItem Value="@role.Name">@role.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions>
|
||||
<MudButton OnClick="CreateNewUser" Variant="Variant.Filled" Color="Color.Success">Create user</MudButton>
|
||||
<MudButton OnClick="Cancel" Variant="Variant.Filled" Color="Color.Error">Cancel</MudButton>
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
|
||||
@code
|
||||
{
|
||||
[Parameter] public required List<IdentityRole> Roles { get; set; }
|
||||
|
||||
[CascadingParameter]
|
||||
public IMudDialogInstance MudDialog { get; set; } = null!;
|
||||
|
||||
private string _newUsername = string.Empty;
|
||||
private string _newUserRole = string.Empty;
|
||||
|
||||
private async Task CreateNewUser()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_newUsername) || string.IsNullOrWhiteSpace(_newUserRole))
|
||||
{
|
||||
Snackbar.Add("Add Username and Role" , Severity.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
ApplicationUser newUser = new ApplicationUser
|
||||
{
|
||||
UserName = _newUsername,
|
||||
EmailConfirmed = true
|
||||
};
|
||||
|
||||
var result = await UserManager.CreateAsync(newUser, "NewPassword123!");
|
||||
|
||||
if(result.Succeeded)
|
||||
{
|
||||
await UserManager.AddToRoleAsync(newUser, _newUserRole);
|
||||
MudDialog.Close(DialogResult.Ok(newUser));
|
||||
return;
|
||||
}
|
||||
|
||||
//Snackbar.Add("User could not be created", Severity.Error);
|
||||
}
|
||||
|
||||
private async Task Cancel()
|
||||
{
|
||||
MudDialog.Cancel();
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,15 @@
|
||||
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
@attribute [Authorize(Roles = "Admin")]
|
||||
|
||||
<h3>Index</h3>
|
||||
|
||||
<MudLink Href="AdminSettings/CouchLogSettings">CouchLog Settings</MudLink>
|
||||
<MudLink Href="AdminSettings/UserManagement">User Management</MudLink>
|
||||
|
||||
@code {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,115 +1,51 @@
|
||||
@page "/AdminSettings/UserManagement"
|
||||
@rendermode InteractiveServer
|
||||
|
||||
@using CouchLog.Components.AdminSettings.Pages.Dialogs
|
||||
@using CouchLog.Data
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using Microsoft.AspNetCore.Components.QuickGrid
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
|
||||
@inject ApplicationDbContext CouchLogDB
|
||||
@inject ApplicationDbContext CouchLogDb
|
||||
@inject UserManager<ApplicationUser> UserManager
|
||||
@inject RoleManager<IdentityRole> RoleManager
|
||||
@inject AuthenticationStateProvider AuthenticationStateProvider
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IDialogService DialogService
|
||||
@inject ISnackbar Snackbar
|
||||
|
||||
@attribute [Authorize(Roles = "Admin")]
|
||||
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<h3 class="mb-0">UserManagement</h3>
|
||||
<MudStack Row="true">
|
||||
<MudText Typo="Typo.h3">UserManagement</MudText>
|
||||
<MudSpacer/>
|
||||
<MudFab StartIcon="@Icons.Material.Filled.Add" Color="Color.Primary" OnClick="OpenCreateUserDialog"/>
|
||||
</MudStack>
|
||||
|
||||
<button type="button"
|
||||
class="btn btn-primary"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#exampleModal">
|
||||
Add User
|
||||
</button>
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
<div>
|
||||
<QuickGrid Items="@gridUsers.AsQueryable()">
|
||||
<PropertyColumn Title="#" Property="@(u => u.Index)" />
|
||||
<PropertyColumn Title="Username" Property="@(u => u.UserName)" />
|
||||
<PropertyColumn Title="Role" Property="@(u => u.Role)" />
|
||||
|
||||
<TemplateColumn Title="">
|
||||
@if(context.UserId != currentUserId)
|
||||
<MudDataGrid Items="_gridUsers" Filterable="false" SortMode="@SortMode.Single" Groupable="false">
|
||||
<Columns>
|
||||
<PropertyColumn Property="arg => arg.Index " Title="Index"/>
|
||||
<PropertyColumn Property="arg => arg.UserId" Title="User Id"/>
|
||||
<PropertyColumn Property="arg => arg.UserName" Title="User Name"/>
|
||||
<PropertyColumn Property="arg => arg.Role" Title="Role"/>
|
||||
<TemplateColumn>
|
||||
<CellTemplate>
|
||||
@if (context.Item.UserId != _currentUserId)
|
||||
{
|
||||
<button class="btn btn-danger btn-sm" @onclick="() => DeleteUser(context)">Delete</button>
|
||||
<MudFab Color="Color.Error" StartIcon="@Icons.Material.Filled.Delete" OnClick="@(() => DeleteUser(context.Item))"/>
|
||||
}
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
</QuickGrid>
|
||||
</div>
|
||||
<!-- #region UserCreate Modal -->
|
||||
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true" style="color: black">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" style="color: black" id="exampleModalLabel">Create User</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- 1. Username Input mit Binding und Bootstrap Klasse -->
|
||||
<div class="mb-3">
|
||||
<label for="newUsernameInput" class="form-label">Username:</label>
|
||||
<input type="text" class="form-control" id="newUsernameInput" @bind="newUsername" />
|
||||
</div>
|
||||
|
||||
<!-- 2. Select mit Binding -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Role:</label>
|
||||
<select class="form-select" @bind="newUserRoleId">
|
||||
<!-- WICHTIG: Eine leere Option als Standard, damit man weiß, ob etwas gewählt wurde -->
|
||||
<option value="" selected disabled>Bitte Rolle wählen...</option>
|
||||
|
||||
@foreach (var role in roles)
|
||||
{
|
||||
<option value="@role.Id">@role.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary" @onclick="CreateUserAsync">Create User</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- #endregion -->
|
||||
</Columns>
|
||||
</MudDataGrid>
|
||||
|
||||
@code {
|
||||
|
||||
string newUsername = "";
|
||||
string newUserRoleId = "";
|
||||
List<UserGridItem> gridUsers = new();
|
||||
List<IdentityRole> roles = new();
|
||||
string? currentUserId;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
||||
currentUserId = authState.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
|
||||
|
||||
var users = await CouchLogDB.Users.ToListAsync();
|
||||
roles = await CouchLogDB.Roles.ToListAsync();
|
||||
int index = 1;
|
||||
|
||||
gridUsers.Clear();
|
||||
|
||||
foreach (var user in users)
|
||||
{
|
||||
var role = await UserManager.GetRolesAsync(user);
|
||||
|
||||
gridUsers.Add(new UserGridItem
|
||||
{
|
||||
Index = index++,
|
||||
UserId = user.Id,
|
||||
UserName = user.UserName!,
|
||||
Role = role.FirstOrDefault() ?? "-"
|
||||
});
|
||||
}
|
||||
}
|
||||
private string? _currentUserId;
|
||||
private List<ApplicationUser> _users = new();
|
||||
private List<IdentityRole> _roles = new();
|
||||
private List<UserGridItem> _gridUsers = new();
|
||||
|
||||
public class UserGridItem
|
||||
{
|
||||
@@ -119,9 +55,59 @@
|
||||
public string Role { get; set; } = "";
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
||||
_currentUserId = authState.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
|
||||
|
||||
var users = await CouchLogDb.Users.ToListAsync();
|
||||
_roles = await CouchLogDb.Roles.ToListAsync();
|
||||
|
||||
await CreateGridUserObjects();
|
||||
}
|
||||
|
||||
private async Task CreateGridUserObjects()
|
||||
{
|
||||
_gridUsers.Clear();
|
||||
|
||||
var users = await CouchLogDb.Users.ToListAsync();
|
||||
int index = 1;
|
||||
|
||||
foreach (var user in users)
|
||||
{
|
||||
|
||||
var role = await UserManager.GetRolesAsync(user);
|
||||
|
||||
_gridUsers.Add(new UserGridItem
|
||||
{
|
||||
Index = index++,
|
||||
UserId = user.Id,
|
||||
UserName = user.UserName!,
|
||||
Role = role.FirstOrDefault() ?? "-"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OpenCreateUserDialog()
|
||||
{
|
||||
var parameters = new DialogParameters<CreateUserDialog>
|
||||
{
|
||||
{ x => x.Roles, _roles }
|
||||
};
|
||||
|
||||
var dialog = await DialogService.ShowAsync<CreateUserDialog>("Create User", parameters);
|
||||
var result = await dialog.Result;
|
||||
if (!result!.Canceled && result.Data is ApplicationUser newUser)
|
||||
{
|
||||
Snackbar.Add("User created", Severity.Success);
|
||||
await CreateGridUserObjects();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
async Task DeleteUser(UserGridItem user)
|
||||
{
|
||||
if (user.UserId == currentUserId)
|
||||
if (user.UserId == _currentUserId)
|
||||
return;
|
||||
|
||||
var identityUser = await UserManager.FindByIdAsync(user.UserId);
|
||||
@@ -133,48 +119,12 @@
|
||||
|
||||
if (result.Succeeded)
|
||||
{
|
||||
gridUsers.Remove(user);
|
||||
_gridUsers.Remove(user);
|
||||
StateHasChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Optional: Fehler anzeigen
|
||||
Snackbar.Add(result.Errors.ToString()!, Severity.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CreateUserAsync()
|
||||
{
|
||||
// Validierung
|
||||
if (string.IsNullOrWhiteSpace(newUsername) || string.IsNullOrWhiteSpace(newUserRoleId))
|
||||
{
|
||||
// Fehlermeldung anzeigen oder abbrechen
|
||||
Console.WriteLine("Bitte Benutzername und Rolle angeben.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Hier deine Logik zum Erstellen des Users
|
||||
var roleIdToUse = newUserRoleId;
|
||||
var usernameToUse = newUsername;
|
||||
|
||||
ApplicationUser newUser = new ApplicationUser
|
||||
{
|
||||
UserName = newUsername,
|
||||
EmailConfirmed = true
|
||||
};
|
||||
|
||||
var result = await UserManager.CreateAsync(newUser, "NewPassword123!");
|
||||
|
||||
IdentityRole roleName = roles.FirstOrDefault(r => r.Id == newUserRoleId);
|
||||
|
||||
if(result.Succeeded)
|
||||
{
|
||||
await UserManager.AddToRoleAsync(newUser, roleName.Name);
|
||||
}
|
||||
|
||||
// Modal schließen oder Formular zurücksetzen
|
||||
newUsername = "";
|
||||
newUserRoleId = "";
|
||||
|
||||
NavigationManager.NavigateTo(NavigationManager.Uri, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,17 +5,27 @@
|
||||
|
||||
@attribute [Authorize(Roles = "Admin")]
|
||||
|
||||
<h1>Manage CouchLog</h1>
|
||||
<MudText Typo="Typo.h1">Manage CouchLog</MudText>
|
||||
|
||||
<div>
|
||||
<h2></h2>
|
||||
<hr />
|
||||
<div class="row">
|
||||
<div class="col-lg-3">
|
||||
<AdminSettingsNavMenu />
|
||||
</div>
|
||||
<div class="col-lg-9">
|
||||
<MudContainer MaxWidth="MaxWidth.False" Class="pa-4">
|
||||
<MudGrid>
|
||||
<MudItem xs="12" md="3" lg="2">
|
||||
<MudNavMenu>
|
||||
<MudNavLink Href="/AdminSettings/CouchLogSettings"
|
||||
Icon="@Icons.Material.Filled.Settings">
|
||||
CouchLog Settings
|
||||
</MudNavLink>
|
||||
|
||||
<MudNavLink Href="/AdminSettings/UserManagement"
|
||||
Match="NavLinkMatch.All"
|
||||
Icon="@Icons.Material.Filled.People">
|
||||
User Management
|
||||
</MudNavLink>
|
||||
</MudNavMenu>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" md="9" lg="10">
|
||||
@Body
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
@@ -1,18 +0,0 @@
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
@using CouchLog.Data
|
||||
|
||||
@inject SignInManager<ApplicationUser> SignInManager
|
||||
|
||||
<ul class="nav nav-pills flex-column">
|
||||
<li class="nav-item">
|
||||
<NavLink class="nav-link" href="/AdminSettings/UserManagement" Match="NavLinkMatch.All">User Management</NavLink>
|
||||
</li>
|
||||
<!--
|
||||
<li class="nav-item">
|
||||
<NavLink class="nav-link" href=""></NavLink>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<NavLink class="nav-link" href=""></NavLink>
|
||||
</li>
|
||||
-->
|
||||
</ul>
|
||||
@@ -1,23 +1,32 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<base href="/" />
|
||||
<link rel="stylesheet" href="@Assets["lib/bootstrap/dist/css/bootstrap.min.css"]" />
|
||||
<link rel="stylesheet" href="@Assets["app.css"]" />
|
||||
<link rel="stylesheet" href="@Assets["CouchLog.styles.css"]" />
|
||||
<ImportMap />
|
||||
<HeadOutlet />
|
||||
|
||||
@* Rendermode get's hand over dynamic *@
|
||||
<HeadOutlet @rendermode="RenderModeForPage" />
|
||||
|
||||
<!-- #MudBlazor -->
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
|
||||
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
|
||||
<!-- #endregion -->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<Routes />
|
||||
@* Rendermode get's hand over dynamic *@
|
||||
<Routes @rendermode="RenderModeForPage" />
|
||||
<script src="_framework/blazor.web.js"></script>
|
||||
<script src="lib/bootstrap/dist/js/bootstrap.js"></script>
|
||||
<script src="lib/bootstrap/dist/js/bootstrap.min.js"></script>
|
||||
<script src="lib/bootstrap/dist/js/site.js"></script>
|
||||
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@code {
|
||||
[CascadingParameter]
|
||||
private HttpContext HttpContext { get; set; } = default!;
|
||||
|
||||
private Microsoft.AspNetCore.Components.IComponentRenderMode? RenderModeForPage => HttpContext.Request.Path.StartsWithSegments("/Account") ? null : Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
@inherits LayoutComponentBase
|
||||
@using MudBlazor
|
||||
|
||||
<MudThemeProvider IsDarkMode="true" />
|
||||
<MudDialogProvider />
|
||||
<MudSnackbarProvider />
|
||||
|
||||
<MudLayout>
|
||||
<MudMainContent>
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="mt-8">
|
||||
@Body
|
||||
</MudContainer>
|
||||
</MudMainContent>
|
||||
</MudLayout>
|
||||
@@ -1,19 +1,40 @@
|
||||
@inherits LayoutComponentBase
|
||||
@using MudBlazor
|
||||
|
||||
<div class="page">
|
||||
<div class="sidebar">
|
||||
<MudThemeProvider @bind-IsDarkMode="@_isDarkMode" />
|
||||
<MudDialogProvider />
|
||||
<MudSnackbarProvider />
|
||||
<MudPopoverProvider />
|
||||
|
||||
<MudLayout>
|
||||
<MudAppBar Color="Color.Primary" Fixed="true">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@((e) => DrawerToggle())" />
|
||||
<MudText Typo="Typo.h6">CouchLog</MudText>
|
||||
</MudAppBar>
|
||||
|
||||
<MudDrawer @bind-Open="@_drawerOpen" ClipMode="DrawerClipMode.Always" Elevation="1">
|
||||
<NavMenu />
|
||||
</div>
|
||||
</MudDrawer>
|
||||
|
||||
<main>
|
||||
<article class="content px-4">
|
||||
<MudMainContent>
|
||||
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="mt-4">
|
||||
@Body
|
||||
</article>
|
||||
</main>
|
||||
</MudContainer>
|
||||
</MudMainContent>
|
||||
</MudLayout>
|
||||
|
||||
<div id="blazor-error-ui">
|
||||
An unhandled error has occurred.
|
||||
<a href="" class="reload">Reload</a>
|
||||
<a class="dismiss">🗙</a>
|
||||
</div>
|
||||
|
||||
<div id="blazor-error-ui" data-nosnippet>
|
||||
An unhandled error has occurred.
|
||||
<a href="." class="reload">Reload</a>
|
||||
<span class="dismiss">🗙</span>
|
||||
</div>
|
||||
@code {
|
||||
bool _drawerOpen = true;
|
||||
bool _isDarkMode = true;
|
||||
|
||||
void DrawerToggle()
|
||||
{
|
||||
_drawerOpen = !_drawerOpen;
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
.page {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
main {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
|
||||
}
|
||||
|
||||
.top-row {
|
||||
background-color: #f7f7f7;
|
||||
border-bottom: 1px solid #d6d5d5;
|
||||
justify-content: flex-end;
|
||||
height: 3.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.top-row ::deep a, .top-row ::deep .btn-link {
|
||||
white-space: nowrap;
|
||||
margin-left: 1.5rem;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.top-row ::deep a:first-child {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
@media (max-width: 640.98px) {
|
||||
.top-row {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.top-row ::deep a, .top-row ::deep .btn-link {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 641px) {
|
||||
.page {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 250px;
|
||||
height: 100vh;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.top-row {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.top-row.auth ::deep a:first-child {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.top-row, article {
|
||||
padding-left: 2rem !important;
|
||||
padding-right: 1.5rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
#blazor-error-ui {
|
||||
color-scheme: light only;
|
||||
background: lightyellow;
|
||||
bottom: 0;
|
||||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
|
||||
box-sizing: border-box;
|
||||
display: none;
|
||||
left: 0;
|
||||
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
#blazor-error-ui .dismiss {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 0.75rem;
|
||||
top: 0.5rem;
|
||||
}
|
||||
@@ -5,81 +5,70 @@
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject AuthenticationStateProvider AuthenticationStateProvider
|
||||
@inject UserManager<ApplicationUser> UserManager
|
||||
@inject ApplicationDbContext CouchLogDB
|
||||
|
||||
<div class="top-row ps-3 navbar navbar-dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="">CouchLog</a>
|
||||
</div>
|
||||
</div>
|
||||
<MudNavMenu>
|
||||
<MudNavLink Href="" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.Home">
|
||||
Home
|
||||
</MudNavLink>
|
||||
|
||||
<input type="checkbox" title="Navigation menu" class="navbar-toggler" />
|
||||
<MudNavLink Href="GlobalList" Icon="@Icons.Material.Filled.List">
|
||||
Globallist
|
||||
</MudNavLink>
|
||||
|
||||
<div class="nav-scrollable" onclick="document.querySelector('.navbar-toggler').click()">
|
||||
<nav class="nav flex-column">
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
|
||||
<span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home
|
||||
</NavLink>
|
||||
</div>
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="GlobalList">
|
||||
<span class="bi bi-plus-square-fill-nav-menu" aria-hidden="true"></span> Global List
|
||||
</NavLink>
|
||||
</div>
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="PrivateList">
|
||||
<span class="bi bi-plus-square-fill-nav-menu" aria-hidden="true"></span> Private List
|
||||
</NavLink>
|
||||
</div>
|
||||
<MudNavLink Href="PrivateList" Icon="@Icons.Material.Filled.Lock">
|
||||
Privatelist
|
||||
</MudNavLink>
|
||||
|
||||
<AuthorizeView Roles="Admin">
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="AdminSettings">
|
||||
<span class="bi bi-plus-square-fill-nav-menu" aria-hidden="true"></span> Admin Settings
|
||||
</NavLink>
|
||||
</div>
|
||||
<MudNavLink Href="AdminSettings" Icon="@Icons.Material.Filled.AdminPanelSettings">
|
||||
Admin Settings
|
||||
</MudNavLink>
|
||||
</AuthorizeView>
|
||||
|
||||
<AuthorizeView>
|
||||
<Authorized>
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="Account/Manage">
|
||||
<span class="bi bi-person-fill-nav-menu" aria-hidden="true"></span> @context.User.Identity?.Name
|
||||
</NavLink>
|
||||
</div>
|
||||
<div class="nav-item px-3">
|
||||
<MudDivider Class="my-2" />
|
||||
<MudNavLink Href="Account/Manage" Icon="@Icons.Material.Filled.Person">
|
||||
@context.User.Identity?.Name
|
||||
</MudNavLink>
|
||||
<form action="Account/Logout" method="post">
|
||||
<AntiforgeryToken />
|
||||
<input type="hidden" name="ReturnUrl" value="@currentUrl" />
|
||||
<button type="submit" class="nav-link">
|
||||
<span class="bi bi-arrow-bar-left-nav-menu" aria-hidden="true"></span> Logout
|
||||
</button>
|
||||
<MudNavLink Icon="@Icons.Material.Filled.Logout"
|
||||
OnClick="@(() => { })"
|
||||
Href="javascript:void(0)"
|
||||
UserAttributes="@(new Dictionary<string, object>
|
||||
{ {"onclick", "this.closest('form').submit()"} })">
|
||||
Logout
|
||||
</MudNavLink>
|
||||
</form>
|
||||
</div>
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="Account/Register">
|
||||
<span class="bi bi-person-nav-menu" aria-hidden="true"></span> Register
|
||||
</NavLink>
|
||||
</div>
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="Account/Login">
|
||||
<span class="bi bi-person-badge-nav-menu" aria-hidden="true"></span> Login
|
||||
</NavLink>
|
||||
</div>
|
||||
<MudDivider Class="my-2" />
|
||||
@if (_isRegistrationAllowed)
|
||||
{
|
||||
<MudNavLink Href="Account/Register" Icon="@Icons.Material.Filled.PersonAdd">
|
||||
Register
|
||||
</MudNavLink>
|
||||
}
|
||||
<MudNavLink Href="Account/Login" Icon="@Icons.Material.Filled.Badge">
|
||||
Login
|
||||
</MudNavLink>
|
||||
</NotAuthorized>
|
||||
</AuthorizeView>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
</MudNavMenu>
|
||||
|
||||
@code {
|
||||
private string? currentUrl;
|
||||
private bool _isRegistrationAllowed;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
currentUrl = NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
|
||||
NavigationManager.LocationChanged += OnLocationChanged;
|
||||
_isRegistrationAllowed = CouchLogDB.AccountsSettings.First().IsRegistrationAllowed;
|
||||
}
|
||||
|
||||
private void OnLocationChanged(object? sender, LocationChangedEventArgs e)
|
||||
@@ -93,4 +82,3 @@
|
||||
NavigationManager.LocationChanged -= OnLocationChanged;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
.navbar-toggler {
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
width: 3.5rem;
|
||||
height: 2.5rem;
|
||||
color: white;
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 1rem;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") no-repeat center/1.75rem rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.navbar-toggler:checked {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.top-row {
|
||||
min-height: 3.5rem;
|
||||
background-color: rgba(0,0,0,0.4);
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.bi {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
margin-right: 0.75rem;
|
||||
top: -1px;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.bi-house-door-fill-nav-menu {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.bi-plus-square-fill-nav-menu {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.bi-list-nested-nav-menu {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.bi-lock-nav-menu {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath d='M8 1a2 2 0 0 1 2 2v4H6V3a2 2 0 0 1 2-2zm3 6V3a3 3 0 0 0-6 0v4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2zM5 8h6a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.bi-person-nav-menu {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-person' viewBox='0 0 16 16'%3E%3Cpath d='M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0Zm4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4Zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10Z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.bi-person-badge-nav-menu {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-person-badge' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 2a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1h-3zM11 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0z'/%3E%3Cpath d='M4.5 0A2.5 2.5 0 0 0 2 2.5V14a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V2.5A2.5 2.5 0 0 0 11.5 0h-7zM3 2.5A1.5 1.5 0 0 1 4.5 1h7A1.5 1.5 0 0 1 13 2.5v10.795a4.2 4.2 0 0 0-.776-.492C11.392 12.387 10.063 12 8 12s-3.392.387-4.224.803a4.2 4.2 0 0 0-.776.492V2.5z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.bi-person-fill-nav-menu {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-person-fill' viewBox='0 0 16 16'%3E%3Cpath d='M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3Zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.bi-arrow-bar-left-nav-menu {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-arrow-bar-left' viewBox='0 0 16 16'%3E%3Cpath d='M12.5 15a.5.5 0 0 1-.5-.5v-13a.5.5 0 0 1 1 0v13a.5.5 0 0 1-.5.5ZM10 8a.5.5 0 0 1-.5.5H3.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L3.707 7.5H9.5a.5.5 0 0 1 .5.5Z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
font-size: 0.9rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.nav-item:first-of-type {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.nav-item:last-of-type {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.nav-item ::deep .nav-link {
|
||||
color: #d7d7d7;
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 3rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nav-item ::deep a.active {
|
||||
background-color: rgba(255,255,255,0.37);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.nav-item ::deep .nav-link:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.nav-scrollable {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navbar-toggler:checked ~ .nav-scrollable {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media (min-width: 641px) {
|
||||
.navbar-toggler {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-scrollable {
|
||||
/* Never collapse the sidebar for wide screens */
|
||||
display: block;
|
||||
|
||||
/* Allow sidebar to scroll for tall menus */
|
||||
height: calc(100vh - 3.5rem);
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
@@ -1,322 +0,0 @@
|
||||
@page "/GlobalList"
|
||||
@rendermode InteractiveServer
|
||||
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using CouchLog.Data
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
|
||||
@inject ApplicationDbContext CouchLogDB
|
||||
@inject UserManager<ApplicationUser> UserManager
|
||||
@inject AuthenticationStateProvider AuthenticationStateProvider
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
@attribute [Authorize]
|
||||
|
||||
<PageTitle>GlobalList</PageTitle>
|
||||
|
||||
<div class="container-fluid mt-4">
|
||||
<!-- #region CreateEntity -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>Global List</h2>
|
||||
<button class="btn btn-info" type="button" @onclick="ToogleCollapseNewGlobalEntity">@(isCollapseNewGlobalEntityOpen ? "X" : "Add Entity")</button>
|
||||
</div>
|
||||
<div class="collapse @(isCollapseNewGlobalEntityOpen ? "show" : "")" id="CollapseCreateNewGlobalEntity">
|
||||
<div class="mb-4 align-items-center CreateNewGlobalEntity-Container">
|
||||
<EditForm Model="@GlobalEntity" OnSubmit="CreateNewGlobalEntity" FormName="CreateNewGlobalEntityForm">
|
||||
<DataAnnotationsValidator />
|
||||
<ValidationSummary />
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="Title" class="form-label">Title</label>
|
||||
<InputText id="Title" class="form-control" @bind-Value="GlobalEntity.Title"></InputText>
|
||||
<ValidationMessage For="@(() => GlobalEntity.Title)"></ValidationMessage>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="Type" class="form-label">Type</label>
|
||||
<select id="Type" class="form-select" @bind="SelectedMediaTypeId">
|
||||
@foreach(MediaType Type in MediaTypes)
|
||||
{
|
||||
<option value="@Type.Id">@Type.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="Picture" class="form-label">Picture</label>
|
||||
<InputFile OnChange="@LoadFiles" accept="image/*"/>
|
||||
@if (!string.IsNullOrEmpty(ImagePreviewUrl))
|
||||
{
|
||||
<img src="@ImagePreviewUrl" style="max-width: 256px; max-height: 256px;" />
|
||||
}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="Genres" class="form-label">Genres</label>
|
||||
@foreach(Genre Genre in Genres)
|
||||
{
|
||||
<button class="btn-primary btn me-2" value="@Genre.Id" type="button" @onclick="() => AddGenreToList(Genre.Id)">@Genre.Name</button>
|
||||
}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<InputCheckbox DisplayName="isPrivate" @bind-Value="isPrivate" ></InputCheckbox>
|
||||
</div>
|
||||
<button type="submit" class="btn-success btn">Create new Global Entity</button>
|
||||
</EditForm>
|
||||
</div>
|
||||
</div>
|
||||
<!-- #endregion -->
|
||||
|
||||
<!-- #region Show Entitys -->
|
||||
<div class="row">
|
||||
@foreach (var Entity in GlobalEntities)
|
||||
{
|
||||
if (!Entity.IsPrivate || (Entity.IsPrivate && (Entity.CreatorId == AppUser.Id)))
|
||||
{
|
||||
<div name="Enity-Container" class="col-12 col-md-6 col-lg-3 mb-4 Entity-Container">
|
||||
<div name="Entity-Container-Card" class="Entity-Container-Card">
|
||||
|
||||
<div class="Entity-Container-Menu-Button dropdown ms-1">
|
||||
<button type="button" class="Entity-Container-Menu-Button btn menu-btn" data-bs-toggle="modal" data-bs-target="#modal-@Entity.Id">⋮</button>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="@Entity.Id" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="staticBackdropLabel">Modal title</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
This is a vertically centered modal.
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary">Understood</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div name="Enity-Container-Image" class="">
|
||||
<a href="javascript:void(0)" class="Entity-Container-Image">
|
||||
<img src="/@Entity.PicturePath" alt="" class="Entity-Container-Image" />
|
||||
</a>
|
||||
</div>
|
||||
<div name="Entity-Container-Data" class="">
|
||||
<h3 class="">@Entity.Title</h3>
|
||||
</div>
|
||||
<div name="Entity-Container-Button" class="d-flex Entity-Container-Button" style="gap: 10px;">
|
||||
<button class="btn btn-info" type="button" @onclick="() => AddToPrivateList(Entity)">
|
||||
@(IsInPrivateList(Entity.Id) ? "Added" : "Add to Private List")
|
||||
</button>
|
||||
<button class="btn btn-info" type="button" @onclick="() => throw new NotImplementedException()">Add to Shared List</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="modal-@Entity.Id" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Optionen</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<button class="btn btn-danger" type="button" @onclick="() => DeleteEntity(Entity)">Delete Entity</button>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Schließen</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<!-- #endregion -->
|
||||
</div>
|
||||
|
||||
@code
|
||||
{
|
||||
private List<MediaType> MediaTypes = new List<MediaType>();
|
||||
private List<Genre> Genres = new List<Genre>();
|
||||
private List<GlobalEntity> GlobalEntities = new List<GlobalEntity>();
|
||||
private List<int> GenreIds = new List<int>();
|
||||
private HashSet<int> UserPrivateEntityIds = new();
|
||||
private string? ImagePreviewUrl;
|
||||
private IBrowserFile? Picture;
|
||||
System.Security.Claims.ClaimsPrincipal User = new();
|
||||
ApplicationUser? AppUser = new();
|
||||
private GlobalEntity GlobalEntity = new();
|
||||
private bool isCollapseNewGlobalEntityOpen = false;
|
||||
private int SelectedMediaTypeId;
|
||||
private bool isPrivate = false;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
GlobalEntities = await CouchLogDB.GlobalEntities.OrderByDescending(Entity => Entity.Id).ToListAsync();
|
||||
MediaTypes = await CouchLogDB.MediaType.OrderBy(Type => Type.Id).ToListAsync();
|
||||
Genres = await CouchLogDB.Genres.OrderBy(Genre => Genre.Id).ToListAsync();
|
||||
|
||||
var AuthState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
||||
User = AuthState.User;
|
||||
|
||||
AppUser = await UserManager.GetUserAsync(User);
|
||||
|
||||
if (AppUser == null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
var TempUserPrivateEntityIds = await CouchLogDB.PrivateEntities
|
||||
.Where(p => p.UserId == AppUser.Id)
|
||||
.Select(p => p.GlobalEntityId)
|
||||
.ToListAsync();
|
||||
|
||||
UserPrivateEntityIds = TempUserPrivateEntityIds.ToHashSet();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
/// <returns></returns>
|
||||
private async Task LoadFiles(InputFileChangeEventArgs eventArgs)
|
||||
{
|
||||
Picture = eventArgs.File;
|
||||
|
||||
//Byte[] Buffer = new byte[Picture.Size];
|
||||
//await Picture.OpenReadStream().ReadAsync(Buffer);
|
||||
//await Picture.OpenReadStream(maxAllowedSize: 10_000_000).ReadAsync(Buffer);
|
||||
|
||||
//string Base64 = Convert.ToBase64String(Buffer);
|
||||
//ImagePreviewUrl = $"data:{Picture.ContentType};base64,{Base64}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
private void ToogleCollapseNewGlobalEntity()
|
||||
{
|
||||
isCollapseNewGlobalEntityOpen = !isCollapseNewGlobalEntityOpen;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task CreateNewGlobalEntity()
|
||||
{
|
||||
if (Picture is null)
|
||||
{
|
||||
throw new InvalidOperationException("No Picture selected.");
|
||||
}
|
||||
|
||||
if (AppUser is null)
|
||||
{
|
||||
throw new InvalidOperationException("User not loaded or not logged in.");
|
||||
}
|
||||
|
||||
//Save Picture and Name it
|
||||
string NewFileName = $"{GlobalEntity.Title.Replace(" ", "-")}-{Guid.NewGuid()}{Path.GetExtension(Picture.Name)}";
|
||||
string PicturePath = Path.Combine("wwwroot", "Pictures", NewFileName);
|
||||
using FileStream FileStream = File.Create(PicturePath);
|
||||
await Picture.OpenReadStream().CopyToAsync(FileStream);
|
||||
//await Picture.OpenReadStream(maxAllowedSize: 10_000_000).CopyToAsync(FileStream);
|
||||
|
||||
GlobalEntity.PicturePath = $"Pictures/{NewFileName}";
|
||||
GlobalEntity.CreatorId = AppUser.Id;
|
||||
GlobalEntity.TypeId = SelectedMediaTypeId;
|
||||
GlobalEntity.CreationTime = DateTime.Now;
|
||||
GlobalEntity.IsPrivate = isPrivate;
|
||||
|
||||
CouchLogDB.Add(GlobalEntity);
|
||||
await CouchLogDB.SaveChangesAsync();
|
||||
|
||||
foreach(int GenreId in GenreIds)
|
||||
{
|
||||
LinkTableGlobalGenre LinkTableGlobalGenre = new() { GenreId = GenreId, GlobalEntityId = GlobalEntity.Id };
|
||||
CouchLogDB.Add(LinkTableGlobalGenre);
|
||||
}
|
||||
|
||||
await CouchLogDB.SaveChangesAsync();
|
||||
NavigationManager.NavigateTo(NavigationManager.Uri, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="GolbalEntityId"></param>
|
||||
/// <returns></returns>
|
||||
private bool IsInPrivateList(int GolbalEntityId)
|
||||
{
|
||||
return UserPrivateEntityIds.Contains(GolbalEntityId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="GlobalEntity"></param>
|
||||
/// <returns></returns>
|
||||
private async Task AddToPrivateList(GlobalEntity GlobalEntity)
|
||||
{
|
||||
if(User.Identity?.IsAuthenticated == true)
|
||||
{
|
||||
if(!IsInPrivateList(GlobalEntity.Id))
|
||||
{
|
||||
if (AppUser is null)
|
||||
{
|
||||
throw new InvalidOperationException("User not loaded or not logged in.");
|
||||
}
|
||||
|
||||
PrivateEntity PrivateEntity = new()
|
||||
{
|
||||
UserId = AppUser.Id,
|
||||
CreationTime = DateTime.Now,
|
||||
GlobalEntityId = GlobalEntity.Id,
|
||||
UserWatchStatusId = 1,
|
||||
};
|
||||
|
||||
CouchLogDB.PrivateEntities.Add(PrivateEntity);
|
||||
await CouchLogDB.SaveChangesAsync();
|
||||
|
||||
UserPrivateEntityIds.Add(GlobalEntity.Id);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddGenreToList(int GenreId)
|
||||
{
|
||||
if (!GenreIds.Contains(GenreId))
|
||||
{
|
||||
GenreIds.Add(GenreId);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DeleteEntity(GlobalEntity entity)
|
||||
{
|
||||
if(entity.PicturePath != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(Path.Combine("wwwroot", entity.PicturePath));
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
CouchLogDB.GlobalEntities.Remove(entity);
|
||||
|
||||
await CouchLogDB.SaveChangesAsync();
|
||||
|
||||
NavigationManager.NavigateTo(NavigationManager.Uri, true);
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/*For Development*/
|
||||
/** {
|
||||
outline: 1px solid red !important;
|
||||
}*/
|
||||
|
||||
.Entity-Container {
|
||||
color:aliceblue
|
||||
}
|
||||
|
||||
.Entity-Container:hover {
|
||||
color: rgba(0,255,255,0.5);
|
||||
}
|
||||
|
||||
.Entity-Container-Card {
|
||||
position: relative;
|
||||
max-width: 275px;
|
||||
background: #111;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
border-radius: 15px;
|
||||
transition: all 0.5s ease;
|
||||
text-align: center;
|
||||
gap: 0.75rem;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
|
||||
.Entity-Container-Card h2 {
|
||||
color: #0ff;
|
||||
font-size: 2rem;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.Entity-Container-Card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -50%;
|
||||
left: -50%;
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
background: linear-gradient( 0deg, transparent, transparent 30%, rgba(0,255,255,0.3) );
|
||||
transform: rotate(-45deg);
|
||||
transition: all 0.5s ease;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.Entity-Container-Card:hover {
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 0 20px rgba(0,255,255,0.5);
|
||||
}
|
||||
|
||||
.Entity-Container-Card:hover::before {
|
||||
opacity: 1;
|
||||
transform: rotate(-45deg) translateY(100%);
|
||||
}
|
||||
|
||||
.Entity-Container-Image {
|
||||
margin: 4px;
|
||||
margin-top: 6px;
|
||||
max-width: 256px;
|
||||
max-height: 256px;
|
||||
}
|
||||
|
||||
.Entity-Container-Button {
|
||||
display: flex;
|
||||
flex-direction: column
|
||||
}
|
||||
|
||||
.CreateNewGlobalEntity-Container {
|
||||
background: #111;
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.Entity-Container-Menu-Button {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 7.5px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #0dcaf0;
|
||||
font-size: 2.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
@using CouchLog.Data
|
||||
|
||||
<MudCard>
|
||||
<MudPaper Elevation="0" Style="position: relative;" @onmouseenter="@(() => _showEditOverlay = true)" @onmouseleave="@(() => _showEditOverlay = false)">
|
||||
<MudCardMedia Image="@($"{GlobalEntity.PicturePath}?v={DateTime.Now.Ticks}")" Height="400" Style="object-fit: contain;"/>
|
||||
<MudOverlay Visible="@_showEditOverlay" DarkBackground="true" Absolute="true">
|
||||
<MudIconButton Icon="@Icons.Material.Rounded.Edit" Color="Color.Primary" OnClick="@(()=> OnEdit.InvokeAsync(GlobalEntity))" />
|
||||
</MudOverlay>
|
||||
</MudPaper>
|
||||
<MudCardContent>
|
||||
<MudTooltip Text="@GlobalEntity.Title">
|
||||
<MudText Typo="Typo.h5" Style="display: block; max-width: 250px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">@GlobalEntity.Title</MudText>
|
||||
</MudTooltip>
|
||||
</MudCardContent>
|
||||
<MudCardActions>
|
||||
<MudTooltip Text="Add to shared List">
|
||||
<MudIconButton Icon="@Icons.Material.Rounded.People" Color="Color.Primary" OnClick="@(() => OnAddToShared.InvokeAsync(GlobalEntity))" />
|
||||
</MudTooltip>
|
||||
<MudSpacer/>
|
||||
@if (UserPrivateEntityIds.Contains(GlobalEntity.Id))
|
||||
{
|
||||
<MudTooltip Text="Already added to Private List">
|
||||
<MudIconButton Icon="@Icons.Material.Rounded.Check" Color="Color.Primary"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudTooltip Text="Add to private List">
|
||||
<MudIconButton Icon="@Icons.Material.Rounded.Lock" Color="Color.Primary" OnClick="@(() => OnAddToPrivate.InvokeAsync(GlobalEntity))" />
|
||||
</MudTooltip>
|
||||
}
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
|
||||
@code
|
||||
{
|
||||
[Parameter] public GlobalEntity GlobalEntity { get; set; } = null!;
|
||||
[Parameter] public HashSet<int> UserPrivateEntityIds { get; set; } = null!;
|
||||
|
||||
[Parameter] public EventCallback<GlobalEntity> OnAddToPrivate { get; set; }
|
||||
[Parameter] public EventCallback<GlobalEntity> OnAddToShared { get; set; }
|
||||
[Parameter] public EventCallback<GlobalEntity> OnEdit { get; set; }
|
||||
|
||||
private bool _showEditOverlay;
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
@using CouchLog.Data
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
|
||||
@inject ApplicationDbContext CouchLogDb
|
||||
@inject UserManager<ApplicationUser> UserManager
|
||||
@inject AuthenticationStateProvider AuthenticationStateProvider
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject ISnackbar Snackbar
|
||||
|
||||
<style>
|
||||
.mud-file-upload-dragarea {
|
||||
height: 400px;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<MudDialog>
|
||||
<TitleContent>
|
||||
<MudText Typo="Typo.h6">Add Global Entity</MudText>
|
||||
</TitleContent>
|
||||
|
||||
<DialogContent>
|
||||
<EditForm EditContext="_editContext" OnSubmit="HandleSubmit" id="New-Global-Entity-Form">
|
||||
<DataAnnotationsValidator />
|
||||
|
||||
<MudStack Row="true" Spacing="3" AlignItems="AlignItems.Start" Style="min-height: 400px;" Breakpoint="Breakpoint.SmAndDown">
|
||||
<!--<editor-fold desc="Picture-Upload">-->
|
||||
<MudPaper Class="pa-0" Elevation="0" Width="280px" MinWidth="280px">
|
||||
@if (!string.IsNullOrWhiteSpace(_imagePreview))
|
||||
{
|
||||
<MudImage Src="@_imagePreview"
|
||||
ObjectFit="ObjectFit.Contain"
|
||||
Class="rounded"
|
||||
Style="width: 280px; height: 400px;"/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudFileUpload @bind-Files="_pictureFile"
|
||||
DragAndDrop="true"
|
||||
OnFilesChanged="OnPictureUploaded"
|
||||
Accept="image/*"
|
||||
InputClass="null"
|
||||
Class="mud-file-upload-dragarea">
|
||||
<SelectedTemplate Context="selectedTemplateContext"/>
|
||||
</MudFileUpload>
|
||||
}
|
||||
</MudPaper>
|
||||
<!--</editor-fold>-->
|
||||
<MudPaper Class="flex-grow-1" Elevation="0" MinWidth="200px">
|
||||
<MudStack Spacing="3">
|
||||
|
||||
<MudTextField @bind-Value="_form.Title"
|
||||
Label="Title"
|
||||
For="@(() => _form.Title)"
|
||||
Variant="Variant.Outlined" />
|
||||
|
||||
<MudSelect T="int"
|
||||
@bind-Value="_selectedMediaTypeId"
|
||||
Label="Type"
|
||||
Variant="Variant.Outlined">
|
||||
@foreach (var type in _mediaTypes)
|
||||
{
|
||||
<MudSelectItem T="int" Value="@type.Id">@type.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
|
||||
<MudSelect T="int"
|
||||
Label="Genres"
|
||||
MultiSelection="true"
|
||||
@bind-SelectedValues="_selectedGenreIds"
|
||||
Variant="Variant.Outlined">
|
||||
@foreach (var genre in _genres)
|
||||
{
|
||||
<MudSelectItem T="int" Value="@genre.Id">@genre.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudCheckBox @bind-Value="_isPrivate" Label="Is Private" Color="Color.Primary" />
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudStack>
|
||||
</EditForm>
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions>
|
||||
<MudButton OnClick="Cancel" Variant="Variant.Filled" Color="Color.Error" Disabled="_isSaving" Class="mt-3">Cancel</MudButton>
|
||||
<MudButton ButtonType="ButtonType.Submit" Variant="Variant.Filled" Color="Color.Success" Disabled="_isSaving" Class="mt-3" form="New-Global-Entity-Form">
|
||||
@if (_isSaving)
|
||||
{
|
||||
<MudProgressCircular Indeterminate="true" Size="Size.Small" Class="mr-2"/>
|
||||
<span>Saving...</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>Create Global Entity</span>
|
||||
}
|
||||
</MudButton>
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
|
||||
@code {
|
||||
[CascadingParameter]
|
||||
private IMudDialogInstance MudDialog { get; set; } = null!;
|
||||
|
||||
private ApplicationUser? _appUser;
|
||||
private EditContext _editContext = null!;
|
||||
|
||||
private List<MediaType> _mediaTypes = new();
|
||||
private List<Genre> _genres = new();
|
||||
|
||||
private GlobalEntityFormModel _form = new();
|
||||
private string? _imagePreview;
|
||||
private int _selectedMediaTypeId;
|
||||
private bool _isPrivate;
|
||||
private bool _isSaving;
|
||||
private IReadOnlyCollection<int> _selectedGenreIds = Array.Empty<int>();
|
||||
|
||||
//Picture
|
||||
private IBrowserFile? _pictureFile;
|
||||
private string _pictureBase64 = null!;
|
||||
private string? _pictureContentType;
|
||||
private string? _pictureExtension;
|
||||
|
||||
private class GlobalEntityFormModel
|
||||
{
|
||||
[Required(ErrorMessage = "Title is required.")]
|
||||
[MaxLength(200, ErrorMessage = "Title may not exceed 200 characters.")]
|
||||
public string Title { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_editContext = new EditContext(_form);
|
||||
|
||||
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
||||
_appUser = await UserManager.GetUserAsync(authState.User);
|
||||
|
||||
if (_appUser is null)
|
||||
{
|
||||
Snackbar.Add("Not authenticated.", Severity.Error);
|
||||
MudDialog.Cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
_mediaTypes = await CouchLogDb.MediaType.OrderBy(t => t.Id).ToListAsync();
|
||||
_genres = await CouchLogDb.Genres.OrderBy(t => t.Id).ToListAsync();
|
||||
|
||||
if (_mediaTypes.Count > 0)
|
||||
_selectedMediaTypeId = _mediaTypes.First().Id;
|
||||
}
|
||||
|
||||
private async Task OnPictureUploaded()
|
||||
{
|
||||
if (_pictureFile == null)
|
||||
{
|
||||
Snackbar.Add("No file selected!", Severity.Warning);
|
||||
return;
|
||||
}
|
||||
if (_pictureFile.Size > 5242880)
|
||||
{
|
||||
Snackbar.Add("File size exceeds 5MB!", Severity.Error);
|
||||
return;
|
||||
}
|
||||
await using var stream = _pictureFile.OpenReadStream(5242880);
|
||||
using var ms = new MemoryStream();
|
||||
await stream.CopyToAsync(ms);
|
||||
|
||||
_pictureContentType = _pictureFile.ContentType;
|
||||
_pictureExtension = Path.GetExtension(_pictureFile.Name);
|
||||
|
||||
_pictureBase64 = Convert.ToBase64String(ms.ToArray());
|
||||
_imagePreview = $"data:{_pictureFile.ContentType};base64,{_pictureBase64}";
|
||||
}
|
||||
|
||||
private void Cancel() => MudDialog.Cancel();
|
||||
|
||||
private async Task HandleSubmit(EditContext ctx)
|
||||
{
|
||||
if (!ctx.Validate()) return;
|
||||
|
||||
if (_pictureFile is null)
|
||||
{
|
||||
Snackbar.Add("Please upload a picture.", Severity.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_selectedMediaTypeId == 0)
|
||||
{
|
||||
Snackbar.Add("Please select a media type.", Severity.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
_isSaving = true;
|
||||
|
||||
try
|
||||
{
|
||||
string fileName = $"{Guid.NewGuid()}{_pictureExtension}";
|
||||
string picturePath = Path.Combine("wwwroot", "Pictures", fileName);
|
||||
|
||||
await File.WriteAllBytesAsync(picturePath, Convert.FromBase64String(_pictureBase64));
|
||||
|
||||
var entity = new GlobalEntity
|
||||
{
|
||||
Title = _form.Title,
|
||||
PicturePath = $"Pictures/{fileName}",
|
||||
CreatorId = _appUser!.Id,
|
||||
TypeId = _selectedMediaTypeId,
|
||||
CreationTime = DateTime.UtcNow,
|
||||
IsPrivate = _isPrivate
|
||||
};
|
||||
|
||||
CouchLogDb.Add(entity);
|
||||
await CouchLogDb.SaveChangesAsync();
|
||||
|
||||
foreach (int genreId in _selectedGenreIds)
|
||||
{
|
||||
CouchLogDb.Add(new LinkTableGlobalGenre
|
||||
{
|
||||
GenreId = genreId,
|
||||
GlobalEntityId = entity.Id
|
||||
});
|
||||
}
|
||||
|
||||
await CouchLogDb.SaveChangesAsync();
|
||||
|
||||
Snackbar.Add("Global Entity created!", Severity.Success);
|
||||
MudDialog.Close(DialogResult.Ok(entity));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Snackbar.Add($"Error: {ex.Message}", Severity.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isSaving = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,248 @@
|
||||
@page "/GlobalList"
|
||||
@rendermode InteractiveServer
|
||||
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using CouchLog.Data
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using CouchLog.Components.Pages.GlobalList.Dialogs
|
||||
@using CouchLog.Components.Pages.GlobalList.Components
|
||||
|
||||
@inject ApplicationDbContext CouchLogDb
|
||||
@inject UserManager<ApplicationUser> UserManager
|
||||
@inject AuthenticationStateProvider AuthenticationStateProvider
|
||||
@inject IDialogService DialogService
|
||||
@inject ISnackbar Snackbar
|
||||
|
||||
@attribute [Authorize]
|
||||
|
||||
<PageTitle>GlobalList</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.False">
|
||||
@*Top of the Page*@
|
||||
<MudContainer>
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center">
|
||||
@*Page Title*@
|
||||
<MudText Typo="Typo.h3" Style="font-weight: bold;">Global List</MudText>
|
||||
|
||||
@*Spacer*@
|
||||
<MudSpacer />
|
||||
|
||||
@*Button for adding GlobalEntity*@
|
||||
<MudTooltip Text="Add GlobalEntity">
|
||||
<MudFab StartIcon="@Icons.Material.Filled.Add" Color="Color.Primary" OnClick="OpenAddNewGlobalEntityDialog"/>
|
||||
</MudTooltip>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
|
||||
<br/>
|
||||
|
||||
<MudContainer>
|
||||
<MudPaper Class="pa-2" Elevation="1">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
||||
@*Search bar*@
|
||||
<MudTextField @bind-Value="_searchString"
|
||||
Placeholder="Search..."
|
||||
Adornment="Adornment.Start"
|
||||
AdornmentIcon="@Icons.Material.Filled.Search"
|
||||
Immediate="true"
|
||||
Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense"
|
||||
Style="max-width: 300px;"/>
|
||||
@*Refresh button*@
|
||||
@*<MudTooltip Text="Refresh Entities">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Refresh" OnClick="RefreshPage"/>
|
||||
</MudTooltip>*@
|
||||
@*More Filters button*@
|
||||
<MudTooltip Text="More filters">
|
||||
<MudIconButton Icon="@(_showFilters
|
||||
? Icons.Material.Filled.ExpandLess
|
||||
: Icons.Material.Filled.FilterList)"
|
||||
OnClick="@(() => _showFilters = !_showFilters)"
|
||||
Color="Color.Default"/>
|
||||
</MudTooltip>
|
||||
</MudStack>
|
||||
<MudCollapse Expanded="_showFilters">
|
||||
@*Entity allready added*@
|
||||
<MudSwitch @bind-Value="_showAlreadyAddedEntities" Color="Color.Primary">
|
||||
Show already added Entities
|
||||
</MudSwitch>
|
||||
@*To be exstendet*@
|
||||
</MudCollapse>
|
||||
</MudPaper>
|
||||
</MudContainer>
|
||||
|
||||
<br/>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.False">
|
||||
<MudGrid Spacing="6" Justify="Justify.Center">
|
||||
@foreach (var globalEntity in VisibleGlobalEntities)
|
||||
{
|
||||
<MudItem xs="12" sm="6" md="4" lg="3" xl="2" Style="min-width: 0;">
|
||||
<GlobalEntityCard GlobalEntity="globalEntity"
|
||||
UserPrivateEntityIds="_userPrivateEntityIds"
|
||||
OnAddToPrivate="AddGlobalEntityToPrivateList"
|
||||
OnAddToShared="AddGlobalEntityToSharedList"
|
||||
OnEdit="OpenEditGlobalEntityDialog"/>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
|
||||
<br/>
|
||||
|
||||
<MudContainer>
|
||||
<MudStack AlignItems="AlignItems.Center">
|
||||
<MudPagination Count="@TotalPages" @bind-Selected="_currentPage"/>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
</MudContainer>
|
||||
|
||||
@code
|
||||
{
|
||||
//Filter
|
||||
private string? _searchString;
|
||||
private bool _showFilters;
|
||||
private bool _showAlreadyAddedEntities = false;
|
||||
private IEnumerable<GlobalEntity> FiltertGlobalEntities => _globalEntities.Where(entity =>
|
||||
(string.IsNullOrWhiteSpace(_searchString) || entity.Title.Contains(_searchString, StringComparison.OrdinalIgnoreCase)) && //Search bar
|
||||
(_showAlreadyAddedEntities || !_userPrivateEntityIds.Contains(entity.Id)) //Filter for already added Entitys
|
||||
);
|
||||
|
||||
//Paging
|
||||
private int _currentPage = 1;
|
||||
private int _pageSize = 12;
|
||||
private int TotalPages => (int)Math.Ceiling(FiltertGlobalEntities.Count() / (double)_pageSize);
|
||||
private IEnumerable<GlobalEntity> VisibleGlobalEntities => FiltertGlobalEntities.Skip((_currentPage - 1) * _pageSize).Take(_pageSize);
|
||||
|
||||
//User
|
||||
private ApplicationUser? _appUser;
|
||||
|
||||
//Core
|
||||
private List<GlobalEntity> _globalEntities = [];
|
||||
private HashSet<int> _userPrivateEntityIds = [];
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
||||
_appUser = await UserManager.GetUserAsync(authState.User);
|
||||
|
||||
if (_appUser is null)
|
||||
{
|
||||
Snackbar.Add("Not authenticated.", Severity.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
_globalEntities = await CouchLogDb.GlobalEntities
|
||||
.OrderByDescending(entity => entity.CreationTime)
|
||||
.Where(entity => !entity.IsPrivate || (entity.IsPrivate && entity.CreatorId == _appUser.Id))
|
||||
.ToListAsync();
|
||||
|
||||
_userPrivateEntityIds = await CouchLogDb.PrivateEntities
|
||||
.Where(entity => entity.UserId == _appUser.Id)
|
||||
.Select(p => p.GlobalEntityId)
|
||||
.ToHashSetAsync();
|
||||
}
|
||||
|
||||
private async Task RefreshPage()
|
||||
{
|
||||
_currentPage = 1;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task OnNewEntity(GlobalEntity entity)
|
||||
{
|
||||
_globalEntities.Insert(0, entity);
|
||||
await RefreshPage();
|
||||
}
|
||||
|
||||
private async Task OpenAddNewGlobalEntityDialog()
|
||||
{
|
||||
var dialog = await DialogService.ShowAsync<AddNewGlobalEntityDialog>("Add new Global Entity");
|
||||
var result = await dialog.Result;
|
||||
if (!result!.Canceled)
|
||||
{
|
||||
var entity = (GlobalEntity)result.Data!;
|
||||
await OnNewEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OpenEditGlobalEntityDialog(GlobalEntity globalEntity)
|
||||
{
|
||||
var parameters = new DialogParameters<EditGlobalEntityDialog>
|
||||
{
|
||||
{ x => x.GlobalEntity, globalEntity },
|
||||
{ x => x.AppUser, _appUser}
|
||||
};
|
||||
|
||||
var dialog = await DialogService.ShowAsync<EditGlobalEntityDialog>("Edit Global Entity", parameters);
|
||||
var result = await dialog.Result;
|
||||
|
||||
if (!result!.Canceled && result.Data is ValueTuple<GlobalEntity, bool> data)
|
||||
{
|
||||
if (data.Item2)
|
||||
{
|
||||
CouchLogDb.GlobalEntities.Remove(data.Item1);
|
||||
await CouchLogDb.SaveChangesAsync();
|
||||
|
||||
_globalEntities.RemoveAll(x => x.Id == data.Item1.Id);
|
||||
|
||||
if (_currentPage > TotalPages)
|
||||
_currentPage = Math.Max(1, TotalPages);
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
if (!data.Item2)
|
||||
{
|
||||
int index = _globalEntities.FindIndex(x => x.Id == data.Item1.Id);
|
||||
if (index >= 0)
|
||||
{
|
||||
_globalEntities[index] = data.Item1;
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task AddGlobalEntityToPrivateList(GlobalEntity globalEntity)
|
||||
{
|
||||
if(_appUser is null) { Snackbar.Add("Not logged in!", Severity.Error); return;}
|
||||
|
||||
if (!await IsInPrivateList(globalEntity.Id))
|
||||
{
|
||||
PrivateEntity privateEntity = new()
|
||||
{
|
||||
UserId = _appUser.Id,
|
||||
CreationTime = DateTime.Now,
|
||||
GlobalEntityId = globalEntity.Id,
|
||||
UserWatchStatusId = 1,
|
||||
//Season = 0,
|
||||
//Episode = 0
|
||||
};
|
||||
|
||||
CouchLogDb.PrivateEntities.Add(privateEntity);
|
||||
await CouchLogDb.SaveChangesAsync();
|
||||
|
||||
_userPrivateEntityIds.Add(globalEntity.Id);
|
||||
StateHasChanged();
|
||||
Snackbar.Add("Added Entity to private List", Severity.Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
Snackbar.Add("Entity already in private List!", Severity.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> IsInPrivateList(int globalEntityId)
|
||||
{
|
||||
if (_appUser is null) return false;
|
||||
|
||||
return await CouchLogDb.PrivateEntities.Where(entity => entity.UserId == _appUser.Id).AnyAsync(entity => entity.GlobalEntityId == globalEntityId);
|
||||
}
|
||||
|
||||
private void AddGlobalEntityToSharedList()
|
||||
{
|
||||
Snackbar.Add("Feature not implemented yet!", Severity.Error);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
@page "/"
|
||||
|
||||
@using CouchLog.Components.Layout
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
|
||||
@attribute [Authorize]
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
@page "/PrivateList"
|
||||
@rendermode InteractiveServer
|
||||
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using CouchLog.Data
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
|
||||
@inject ApplicationDbContext CouchLogDB
|
||||
@inject UserManager<ApplicationUser> UserManager
|
||||
@inject AuthenticationStateProvider AuthenticationStateProvider
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
@attribute [Authorize]
|
||||
|
||||
<PageTitle>Private List</PageTitle>
|
||||
|
||||
<div class="container-fluid mt-4 px-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>Private List</h2>
|
||||
</div>
|
||||
|
||||
<!-- Grid-Layout -->
|
||||
<div class="row g-4">
|
||||
@foreach (var Entity in PrivateEntities)
|
||||
{
|
||||
/*
|
||||
Hier bleiben wir bei col-lg-6 (halbe Bildschirmbreite),
|
||||
wie du es im roten Kasten wolltest.
|
||||
*/
|
||||
<div class="col-12 col-lg-6 col-xxl-4">
|
||||
|
||||
<div class="card shadow-sm border-0 overflow-hidden private-entity-card">
|
||||
<div class="row g-0 h-100">
|
||||
|
||||
<!-- BILD: col-auto sorgt dafür, dass sich die Breite nach CSS richtet -->
|
||||
<div class="col-auto img-wrapper">
|
||||
@if (!string.IsNullOrEmpty(Entity.GlobalEntity?.PicturePath))
|
||||
{
|
||||
<img src="/@Entity.GlobalEntity.PicturePath"
|
||||
class="entity-img"
|
||||
alt="@Entity.GlobalEntity.Title">
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="d-flex align-items-center justify-content-center h-100 bg-light text-muted small px-2">
|
||||
Kein Bild
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- INFO: 'col' nimmt automatisch den RESTLICHEN Platz ein -->
|
||||
<div class="col">
|
||||
<div class="card-body d-flex flex-column h-100 py-2 px-3">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="d-flex justify-content-between align-items-start">
|
||||
<div class="overflow-hidden">
|
||||
<h5 class="card-title fw-bold mb-0 text-truncate">@Entity.GlobalEntity?.Title</h5>
|
||||
<small class="text-muted meta-text">
|
||||
@Entity.CreationTime.ToShortDateString()
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="dropdown ms-1">
|
||||
<button class="btn btn-link menu-btn" type="button" data-bs-toggle="modal" data-bs-target="#modal-@Entity.Id">
|
||||
⋮
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<select class="form-select"
|
||||
value="@Entity.UserWatchStatusId"
|
||||
@onchange="@(e => UpdateWatchStatus(Entity, e.Value))">
|
||||
|
||||
@foreach (var status in userWatchStatuses)
|
||||
{
|
||||
<option value="@status.Id">@status.Name</option>
|
||||
}
|
||||
</select>
|
||||
|
||||
@if (Entity.GlobalEntity?.MediaType.Name == "Series")
|
||||
{
|
||||
<select class="form-select" value="@Entity.Season" @onchange="@(e => UpdateSeason(Entity, e.Value))">
|
||||
@{
|
||||
int currentSeason = Entity.Season ?? 1;
|
||||
|
||||
int startOffsetSeason = currentSeason > 1 ? -1 : 0;
|
||||
}
|
||||
|
||||
@for (int i = startOffsetSeason; i <= 5; i++)
|
||||
{
|
||||
int season = currentSeason + i;
|
||||
|
||||
<option value="@season">
|
||||
Staffel @season
|
||||
</option>
|
||||
}
|
||||
</select>
|
||||
|
||||
<select class="form-select" value="@Entity.Episode" @onchange="@(e => UpdateEpisode(Entity, e.Value))">
|
||||
@{
|
||||
int currentEpisode = Entity.Episode ?? 1;
|
||||
|
||||
int startOffsetEpisode = currentEpisode > 1 ? -1 : 0;
|
||||
}
|
||||
|
||||
@for (int i = startOffsetEpisode; i <= 5; i++)
|
||||
{
|
||||
int episode = currentEpisode + i;
|
||||
|
||||
<option value="@episode">
|
||||
Episode @episode
|
||||
</option>
|
||||
}
|
||||
</select>
|
||||
}
|
||||
|
||||
<!-- Beschreibung -->
|
||||
<!--<p class="card-text text-truncate-multiline flex-grow-1 text-muted small mt-1 mb-2">
|
||||
@(!string.IsNullOrWhiteSpace(Entity.Description)
|
||||
? Entity.Description
|
||||
: (Entity.Description ?? "Keine Beschreibung."))
|
||||
</p>
|
||||
-->
|
||||
<!-- Footer Button -->
|
||||
<div class="mt-auto d-flex justify-content-end">
|
||||
<button class="btn btn-outline-secondary btn-sm btn-details" type="button">Details</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal (unverändert) -->
|
||||
<div class="modal fade" id="modal-@Entity.Id" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Optionen</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">Optionen...</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Schließen</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code
|
||||
{
|
||||
private List<PrivateEntity> PrivateEntities = new List<PrivateEntity>();
|
||||
private List<UserWatchStatus> userWatchStatuses = new List<UserWatchStatus>();
|
||||
ApplicationUser? AppUser = new();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var AuthState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
||||
AppUser = await UserManager.GetUserAsync(AuthState.User);
|
||||
|
||||
if (AppUser != null)
|
||||
{
|
||||
PrivateEntities = await CouchLogDB.PrivateEntities
|
||||
.Where(x => x.UserId == AppUser.Id)
|
||||
.Include(x => x.GlobalEntity)
|
||||
.Include(x => x.UserWatchStatus)
|
||||
.Include(x => x.GlobalEntity.MediaType)
|
||||
.OrderByDescending(Entity => Entity.LastChange ?? Entity.CreationTime)
|
||||
.ToListAsync();
|
||||
|
||||
userWatchStatuses = await CouchLogDB.UserWatchStatuses.OrderByDescending(Entity => Entity.Id).ToListAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateWatchStatus(PrivateEntity entity, object? newValue)
|
||||
{
|
||||
// Wir holen uns die gewählte ID aus dem Dropdown
|
||||
if (int.TryParse(newValue?.ToString(), out int newId))
|
||||
{
|
||||
// 1. ID im Objekt aktualisieren
|
||||
entity.UserWatchStatusId = newId;
|
||||
|
||||
// 2. Navigation Property aktualisieren (damit die UI nicht flackert)
|
||||
// Wir suchen das passende Objekt aus der geladenen Liste
|
||||
entity.UserWatchStatus = userWatchStatuses.FirstOrDefault(s => s.Id == newId);
|
||||
|
||||
// 3. Ab in die Datenbank
|
||||
await CouchLogDB.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateSeason(PrivateEntity entity, object? newSeasonValue)
|
||||
{
|
||||
if(int.TryParse(newSeasonValue?.ToString(), out int newSeason))
|
||||
{
|
||||
entity.Season = newSeason;
|
||||
|
||||
await CouchLogDB.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateEpisode(PrivateEntity entity, object? newEpisodeValue)
|
||||
{
|
||||
if (int.TryParse(newEpisodeValue?.ToString(), out int newEpisode))
|
||||
{
|
||||
entity.Episode = newEpisode;
|
||||
|
||||
await CouchLogDB.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/* PrivateList.razor.css */
|
||||
|
||||
.private-entity-card {
|
||||
height: 220px;
|
||||
background-color: #fff;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.private-entity-card:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;
|
||||
}
|
||||
|
||||
/*
|
||||
NEU: Feste Breite für das Bild!
|
||||
150px Breite bei 220px Höhe passt perfekt für Poster.
|
||||
*/
|
||||
.img-wrapper {
|
||||
width: 150px;
|
||||
background-color: #f0f2f5;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Bild füllt den Wrapper komplett aus */
|
||||
.entity-img {
|
||||
object-fit: cover;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/* Positioniert das Bild oben, falls das Format doch leicht abweicht (Köpfe/Titel sind meist oben) */
|
||||
object-position: top center;
|
||||
}
|
||||
|
||||
.text-truncate-multiline {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.meta-text {
|
||||
font-size: 0.75rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.menu-btn {
|
||||
color: #212529;
|
||||
text-decoration: none;
|
||||
font-size: 1.2rem;
|
||||
line-height: 1;
|
||||
padding: 0 0.25rem;
|
||||
}
|
||||
|
||||
.menu-btn:hover {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.btn-details {
|
||||
font-size: 0.7rem;
|
||||
padding: 0.2rem 0.6rem;
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
@using CouchLog.Data
|
||||
|
||||
<MudCard Elevation="4">
|
||||
<MudCardContent Class="pa-0">
|
||||
<MudGrid Spacing="0">
|
||||
<!--<editor-fold desc="Poster-Image">-->
|
||||
<MudItem xs="4">
|
||||
<MudImage
|
||||
Src="@PrivateEntity.GlobalEntity.PicturePath"
|
||||
Alt=""
|
||||
ObjectFit="ObjectFit.Cover"
|
||||
Style="width: 100%; height: 100%; min-height: 180px; border-radius: 4px 0 0 4px;" />
|
||||
</MudItem>
|
||||
<!--</editor-fold>-->
|
||||
|
||||
<MudItem xs="8">
|
||||
<MudStack Class="pa-3" Spacing="2">
|
||||
<!--<editor-fold desc="Options">-->
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween">
|
||||
<MudTooltip Text="@PrivateEntity.GlobalEntity.Title">
|
||||
<MudText Typo="Typo.h6" Style="display: block; max-width: 250px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">@PrivateEntity.GlobalEntity.Title</MudText>
|
||||
</MudTooltip>
|
||||
<MudMenu Icon="@Icons.Material.Filled.MoreVert" Color="Color.Default" Dense="true">
|
||||
<MudMenuItem>Edit</MudMenuItem>
|
||||
<MudMenuItem OnClick="@(() => OnRemove.InvokeAsync())">Remove</MudMenuItem>
|
||||
</MudMenu>
|
||||
</MudStack>
|
||||
<!--</editor-fold>-->
|
||||
|
||||
<!--<editor-fold desc="Dropdown-States">-->
|
||||
<MudSelect
|
||||
T="int"
|
||||
Value="PrivateEntity.UserWatchStatus!.Id"
|
||||
ValueChanged="@(newStatusId => OnWatchStatusChange.InvokeAsync(newStatusId))"
|
||||
Dense="true"
|
||||
Variant="Variant.Outlined"
|
||||
Label="">
|
||||
@foreach (var status in UserWatchStatuses)
|
||||
{
|
||||
<MudSelectItem Value="status.Id">@status.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<!--</editor-fold>-->
|
||||
|
||||
<!-- @if (PrivateEntity.GlobalEntity.MediaType.Name == "Series" || PrivateEntity.GlobalEntity.MediaType.Name == "Anime") -->
|
||||
<!--{-->
|
||||
<!--<editor-fold desc="Dropdown-Season">-->
|
||||
<MudSelect
|
||||
T="int?"
|
||||
Value="PrivateEntity.Season"
|
||||
ValueChanged="@(newSeason => OnSeasonChange.InvokeAsync(newSeason))"
|
||||
Dense="true"
|
||||
Variant="Variant.Outlined"
|
||||
Label=""
|
||||
Class="@(PrivateEntity.GlobalEntity.MediaType.Name == "Series" ? "" : "invisible")">
|
||||
@{
|
||||
int? currentSeason = PrivateEntity.Season ?? 1;
|
||||
int? startOffsetSeason = currentSeason > 1 ? -1 : 0;
|
||||
}
|
||||
@for (int? i = startOffsetSeason; i <= 5; i++)
|
||||
{
|
||||
int? season = currentSeason + i;
|
||||
<MudSelectItem Value="@season">Staffel @season</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<!--</editor-fold>-->
|
||||
|
||||
<!--<editor-fold desc="Dropdown-Episode">-->
|
||||
<MudSelect
|
||||
T="int?"
|
||||
Value="PrivateEntity.Episode"
|
||||
ValueChanged="@(newEpisode => OnEpisodeChange.InvokeAsync(newEpisode))"
|
||||
Dense="true"
|
||||
Variant="Variant.Outlined"
|
||||
Label=""
|
||||
Class="@(PrivateEntity.GlobalEntity.MediaType.Name == "Series" ? "" : "invisible")">
|
||||
@{
|
||||
int? currentEpisode = PrivateEntity.Episode ?? 1;
|
||||
int? startOffsetEpisode = currentEpisode > 1 ? -1 : 0;
|
||||
}
|
||||
@for (int? i = startOffsetEpisode; i <= 5; i++)
|
||||
{
|
||||
int? episode = currentEpisode + i;
|
||||
<MudSelectItem Value="@episode">Episode @episode</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<!--</editor-fold>-->
|
||||
<!--}-->
|
||||
|
||||
<!--<editor-fold desc="Details Button">-->
|
||||
<MudStack Row="true" Justify="Justify.FlexEnd">
|
||||
<MudButton
|
||||
Variant="Variant.Outlined"
|
||||
Size="Size.Small">
|
||||
Details
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
<!--</editor-fold>-->
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
|
||||
@code
|
||||
{
|
||||
[Parameter] public PrivateEntity PrivateEntity { get; set; } = null!;
|
||||
[Parameter] public List<UserWatchStatus> UserWatchStatuses { get; set; } = null!;
|
||||
|
||||
[Parameter] public EventCallback<int> OnWatchStatusChange { get; set; }
|
||||
[Parameter] public EventCallback<int?> OnSeasonChange { get; set; }
|
||||
[Parameter] public EventCallback<int?> OnEpisodeChange { get; set; }
|
||||
|
||||
[Parameter] public EventCallback OnRemove { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
@page "/PrivateList"
|
||||
@rendermode InteractiveServer
|
||||
|
||||
@using CouchLog.Components.Pages.PrivateList.Components
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using CouchLog.Data
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
|
||||
@inject ApplicationDbContext CouchLogDb
|
||||
@inject UserManager<ApplicationUser> UserManager
|
||||
@inject AuthenticationStateProvider AuthenticationStateProvider
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
@attribute [Authorize]
|
||||
|
||||
<PageTitle>Private List</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.False">
|
||||
@*Top of the Page*@
|
||||
<MudContainer>
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center">
|
||||
@*Page Title*@
|
||||
<MudText Typo="Typo.h3" Style="font-weight: bold;">Private List</MudText>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
|
||||
<br/>
|
||||
|
||||
<MudContainer>
|
||||
<MudPaper Class="pa-2" Elevation="1">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
||||
@*Search bar*@
|
||||
<MudTextField @bind-Value="_searchString"
|
||||
Placeholder="Search..."
|
||||
Adornment="Adornment.Start"
|
||||
AdornmentIcon="@Icons.Material.Filled.Search"
|
||||
Immediate="true"
|
||||
Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense"
|
||||
Style="max-width: 300px;"/>
|
||||
@*Refresh button*@
|
||||
@*<MudTooltip Text="Refresh Entities">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Refresh" OnClick="RefreshPage"/>
|
||||
</MudTooltip>*@
|
||||
@*More Filters button*@
|
||||
<MudTooltip Text="More filters">
|
||||
<MudIconButton Icon="@(_showFilters
|
||||
? Icons.Material.Filled.ExpandLess
|
||||
: Icons.Material.Filled.FilterList)"
|
||||
OnClick="@(() => _showFilters = !_showFilters)"
|
||||
Color="Color.Default"/>
|
||||
</MudTooltip>
|
||||
</MudStack>
|
||||
<MudCollapse Expanded="_showFilters">
|
||||
No Filters avalible yet!
|
||||
<!--@*Entity allready added*@
|
||||
<MudSwitch @bind-Value="_showAlreadyAddedEntities" Color="Color.Primary">
|
||||
Show already added Entities
|
||||
</MudSwitch>-->
|
||||
@*To be exstendet*@
|
||||
</MudCollapse>
|
||||
</MudPaper>
|
||||
</MudContainer>
|
||||
|
||||
<br/>
|
||||
|
||||
|
||||
<!--<editor-fold desc="Active Watching">-->
|
||||
<MudContainer MaxWidth="MaxWidth.False">
|
||||
<MudText Typo="Typo.h4">Active Watching</MudText>
|
||||
<br/>
|
||||
<MudGrid Spacing="6" Justify="Justify.Center">
|
||||
@foreach (var privateEntity in VisibleActiveWatchingEntities)
|
||||
{
|
||||
<MudItem xs="12" sm="8" md="6" lg="4">
|
||||
<PrivateEntityCard
|
||||
PrivateEntity="privateEntity"
|
||||
UserWatchStatuses="_userWatchStatuses"
|
||||
OnWatchStatusChange="@(newStatusId => ChangeWatchStatus(privateEntity, newStatusId))"
|
||||
OnSeasonChange="@(newSeason => ChangeSeason(privateEntity, newSeason))"
|
||||
OnEpisodeChange="@(newEpisode => ChangeEpisode(privateEntity, newEpisode))"
|
||||
OnRemove="() => RemovePrivateEntity(privateEntity)"
|
||||
/>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
<br/>
|
||||
|
||||
<MudContainer>
|
||||
<MudStack AlignItems="AlignItems.Center">
|
||||
<MudPagination Count="@TotalPagesActiveWatching" @bind-Selected="_currentActiveWatchingPage"/>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
<!--</editor-fold>-->
|
||||
|
||||
<br/>
|
||||
|
||||
<!--<editor-fold desc="Library">-->
|
||||
<MudContainer MaxWidth="MaxWidth.False">
|
||||
<MudText Typo="Typo.h4">Library</MudText>
|
||||
<MudGrid Spacing="6" Justify="Justify.Center">
|
||||
@foreach (var privateEntity in VisibleLibraryEntities)
|
||||
{
|
||||
<MudItem xs="12" sm="8" md="6" lg="4">
|
||||
<PrivateEntityCard
|
||||
PrivateEntity="privateEntity"
|
||||
UserWatchStatuses="_userWatchStatuses"
|
||||
OnWatchStatusChange="@(newStatusId => ChangeWatchStatus(privateEntity, newStatusId))"
|
||||
OnSeasonChange="@(newSeason => ChangeSeason(privateEntity, newSeason))"
|
||||
OnEpisodeChange="@(newEpisode => ChangeEpisode(privateEntity, newEpisode))"
|
||||
OnRemove="() => RemovePrivateEntity(privateEntity)"
|
||||
/>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
|
||||
<br/>
|
||||
|
||||
<MudContainer>
|
||||
<MudStack AlignItems="AlignItems.Center">
|
||||
<MudPagination Count="@TotalPagesLibrary" @bind-Selected="_currentLibraryPage"/>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
<!--</editor-fold>-->
|
||||
</MudContainer>
|
||||
|
||||
@code
|
||||
{
|
||||
//Filter
|
||||
private string? _searchString;
|
||||
private bool _showFilters;
|
||||
//private bool _showAlreadyAddedEntities = false;
|
||||
private IEnumerable<PrivateEntity> FiltertGlobalEntities => _privateEntities.Where(entity =>
|
||||
(string.IsNullOrWhiteSpace(_searchString) || entity.GlobalEntity.Title.Contains(_searchString, StringComparison.OrdinalIgnoreCase)) //Search bar
|
||||
);
|
||||
|
||||
//Paging Active Watching
|
||||
private int _currentActiveWatchingPage = 1;
|
||||
private readonly int _pageSizeActiveWatching = 12;
|
||||
private int TotalPagesActiveWatching => (int)Math.Ceiling(ActiveWatchingEntities.Count() / (double)_pageSizeActiveWatching);
|
||||
private IEnumerable<PrivateEntity> VisibleActiveWatchingEntities => ActiveWatchingEntities.Skip((_currentActiveWatchingPage - 1) * _pageSizeActiveWatching).Take(_pageSizeActiveWatching);
|
||||
|
||||
//Paging Library
|
||||
private int _currentLibraryPage = 1;
|
||||
private readonly int _pageSizeLibrary = 12;
|
||||
private int TotalPagesLibrary => (int)Math.Ceiling(LibraryEntities.Count() / (double)_pageSizeLibrary);
|
||||
private IEnumerable<PrivateEntity> VisibleLibraryEntities => LibraryEntities.Skip((_currentLibraryPage - 1) * _pageSizeLibrary).Take(_pageSizeLibrary);
|
||||
|
||||
//User
|
||||
private ApplicationUser? _appUser;
|
||||
|
||||
//Entities
|
||||
private List<PrivateEntity> _privateEntities = [];
|
||||
private List<UserWatchStatus> _userWatchStatuses = [];
|
||||
|
||||
private IEnumerable<PrivateEntity> ActiveWatchingEntities => FiltertGlobalEntities.Where(x => x.UserWatchStatus?.Name == "Watching").ToList();
|
||||
private IEnumerable<PrivateEntity> LibraryEntities => FiltertGlobalEntities.Where(x => x.UserWatchStatus?.Name != "Watching").ToList();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await GetPrivateEntities();
|
||||
|
||||
_userWatchStatuses = await CouchLogDb.UserWatchStatuses.OrderBy(entity => entity.Id).ToListAsync();
|
||||
}
|
||||
|
||||
private async Task GetPrivateEntities()
|
||||
{
|
||||
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
||||
_appUser = await UserManager.GetUserAsync(authState.User);
|
||||
|
||||
if (_appUser != null)
|
||||
{
|
||||
_privateEntities = await CouchLogDb.PrivateEntities
|
||||
.Where(x => x.UserId == _appUser.Id)
|
||||
.Include(x => x.GlobalEntity)
|
||||
.Include(x => x.UserWatchStatus)
|
||||
.Include(x => x.GlobalEntity.MediaType)
|
||||
.OrderByDescending(entity => entity.LastChange ?? entity.CreationTime)
|
||||
.ToListAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RefreshPages()
|
||||
{
|
||||
_currentLibraryPage = 1;
|
||||
_currentActiveWatchingPage = 1;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task ChangeWatchStatus(PrivateEntity privateEntity, int newUserWatchStatusId)
|
||||
{
|
||||
privateEntity.UserWatchStatus = _userWatchStatuses.FirstOrDefault(s => s.Id == newUserWatchStatusId);
|
||||
await CouchLogDb.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private async Task ChangeSeason(PrivateEntity privateEntity, int? newSeason)
|
||||
{
|
||||
privateEntity.Season = newSeason;
|
||||
await CouchLogDb.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private async Task ChangeEpisode(PrivateEntity privateEntity, int? newEpisode)
|
||||
{
|
||||
privateEntity.Episode = newEpisode;
|
||||
await CouchLogDb.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private async Task RemovePrivateEntity(PrivateEntity privateEntity)
|
||||
{
|
||||
CouchLogDb.PrivateEntities.Remove(privateEntity);
|
||||
await CouchLogDb.SaveChangesAsync();
|
||||
await GetPrivateEntities();
|
||||
}
|
||||
}
|
||||
@@ -9,3 +9,4 @@
|
||||
@using Microsoft.JSInterop
|
||||
@using CouchLog
|
||||
@using CouchLog.Components
|
||||
@using MudBlazor
|
||||
+15
-13
@@ -7,6 +7,10 @@
|
||||
<OutputType>Exe</OutputType>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<PackAsTool>True</PackAsTool>
|
||||
<Version>0.1.0-nightly.10</Version>
|
||||
<Authors>Penry</Authors>
|
||||
<IsPackable>false</IsPackable>
|
||||
<WarnOnPackingNonPackableProject>false</WarnOnPackingNonPackableProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -58,25 +62,23 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.QuickGrid" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.Build" Version="18.0.2" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Features" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.DotNet.Scaffolding.Shared" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.1">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.QuickGrid" Version="10.0.9" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="10.0.9" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.9" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="10.0.9" />
|
||||
<PackageReference Include="Microsoft.Build" Version="18.7.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.9" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.9">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.1">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.9" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.9" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.9">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="MudBlazor" Version="9.6.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 18
|
||||
VisualStudioVersion = 18.1.11304.174 d18.0
|
||||
VisualStudioVersion = 18.1.11304.174
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CouchLog", "CouchLog.csproj", "{4FBF15C3-5FC5-4605-9EBC-3F7DA1ADC47A}"
|
||||
EndProject
|
||||
|
||||
@@ -23,5 +23,9 @@ namespace CouchLog.Data
|
||||
public DbSet<SharedListEntity> SharedListEntities { get; set; }
|
||||
public DbSet<SharedListLabel> SharedListLabels { get; set; }
|
||||
public DbSet<SharedWatchStatus> SharedWatchStatuses { get; set; }
|
||||
|
||||
//Settings
|
||||
public DbSet<CouchLogState> CouchLogState { get; set; }
|
||||
public DbSet<AccountsSettings> AccountsSettings { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,7 @@ using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace CouchLog.Data
|
||||
{
|
||||
[method: SetsRequiredMembers]
|
||||
public class GlobalEntity()
|
||||
public class GlobalEntity
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
@@ -27,6 +27,6 @@ namespace CouchLog.Data
|
||||
[ForeignKey(nameof(CreatorId))]
|
||||
public virtual ApplicationUser User { get; set; } = null!;
|
||||
|
||||
public virtual ICollection<LinkTablePrivateLabel> LinkTablePrivateLabels { get; set; } = new List<LinkTablePrivateLabel>();
|
||||
public virtual ICollection<LinkTablePrivateLabel> LinkTablePrivateLabels { get; set; } = [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace CouchLog.Data
|
||||
{
|
||||
public class AccountsSettings
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
public bool IsRegistrationAllowed { get; set; }
|
||||
|
||||
//More Options that can be added
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace CouchLog.Data
|
||||
{
|
||||
public class CouchLogState
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public bool IsInitialized { get; set; }
|
||||
public DateTime? InitializationDate { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,978 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using CouchLog.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace CouchLog.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20251229004324_CouchLogState")]
|
||||
partial class CouchLogState
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "10.0.1");
|
||||
|
||||
modelBuilder.Entity("CouchLog.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("TEXT");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasDatabaseName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.CouchLogState", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("InitializationDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsInitialized")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CouchLogState");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.Genre", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Genres");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.GlobalEntity", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CreatorId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsPrivate")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PicturePath")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("TypeId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatorId");
|
||||
|
||||
b.HasIndex("TypeId");
|
||||
|
||||
b.ToTable("GlobalEntities");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.Label", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CreatorId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatorId");
|
||||
|
||||
b.ToTable("Labels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTableGlobalGenre", b =>
|
||||
{
|
||||
b.Property<int>("GlobalEntityId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnOrder(0);
|
||||
|
||||
b.Property<int>("GenreId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnOrder(1);
|
||||
|
||||
b.HasKey("GlobalEntityId", "GenreId");
|
||||
|
||||
b.HasIndex("GenreId");
|
||||
|
||||
b.ToTable("LinkTableGlobalGenre");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTablePrivateLabel", b =>
|
||||
{
|
||||
b.Property<int>("PrivateEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("LabelId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("PrivateEntityId", "LabelId");
|
||||
|
||||
b.HasIndex("LabelId");
|
||||
|
||||
b.ToTable("LinkTablePrivateLabel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTablePrivateStreamingPlatform", b =>
|
||||
{
|
||||
b.Property<int>("PrivateEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("StreamingPlatformId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("SharedListEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("PrivateEntityId", "StreamingPlatformId");
|
||||
|
||||
b.HasIndex("SharedListEntityId");
|
||||
|
||||
b.HasIndex("StreamingPlatformId");
|
||||
|
||||
b.ToTable("LinkTablePrivateStreamingPlatform");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTableSharedLabel", b =>
|
||||
{
|
||||
b.Property<int>("SharedListLabelId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SharedListEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("SharedListLabelId", "SharedListEntityId");
|
||||
|
||||
b.HasIndex("SharedListEntityId");
|
||||
|
||||
b.ToTable("LinkTableSharedLabel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTableSharedUser", b =>
|
||||
{
|
||||
b.Property<int>("SharedListId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("SharedListId", "UserId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("LinkTableSharedUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.MediaType", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("MediaType");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.PrivateEntity", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(1000)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("Episode")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Favorite")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("GlobalEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("Rating")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("Season")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("UserWatchStatusId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GlobalEntityId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.HasIndex("UserWatchStatusId");
|
||||
|
||||
b.ToTable("PrivateEntities");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedList", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(150)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SharedLists");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedListEntity", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(1000)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("Episode")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Favorite")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("GlobalEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("Season")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SharedListId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("SharedWatchStatusId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GlobalEntityId");
|
||||
|
||||
b.HasIndex("SharedListId");
|
||||
|
||||
b.HasIndex("SharedWatchStatusId");
|
||||
|
||||
b.ToTable("SharedListEntities");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedListLabel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("SharedListId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SharedListId");
|
||||
|
||||
b.ToTable("SharedListLabels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedWatchStatus", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ColorCode")
|
||||
.HasMaxLength(7)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("SharedListId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SharedListId");
|
||||
|
||||
b.ToTable("SharedWatchStatuses");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.StreamingPlatform", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PicturePath")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("StreamingPlatforms");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.UserWatchStatus", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ColorCode")
|
||||
.HasMaxLength(7)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("UserWatchStatuses");
|
||||
});
|
||||
|
||||
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("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
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");
|
||||
|
||||
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");
|
||||
|
||||
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("CouchLog.Data.GlobalEntity", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.ApplicationUser", "User")
|
||||
.WithMany("CreatedGlobalEntities")
|
||||
.HasForeignKey("CreatorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.MediaType", "MediaType")
|
||||
.WithMany("GlobalEntities")
|
||||
.HasForeignKey("TypeId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("MediaType");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.Label", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.ApplicationUser", "User")
|
||||
.WithMany("CreatedLabels")
|
||||
.HasForeignKey("CreatorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTableGlobalGenre", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.Genre", "Genre")
|
||||
.WithMany("LinkTableGlobalGenres")
|
||||
.HasForeignKey("GenreId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.GlobalEntity", "GlobalEntity")
|
||||
.WithMany("LinkTableGlobalGenres")
|
||||
.HasForeignKey("GlobalEntityId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Genre");
|
||||
|
||||
b.Navigation("GlobalEntity");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTablePrivateLabel", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.Label", "Label")
|
||||
.WithMany("LinkTablePrivateLabels")
|
||||
.HasForeignKey("LabelId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.PrivateEntity", "PrivateEntity")
|
||||
.WithMany("PrivateEntityLabels")
|
||||
.HasForeignKey("PrivateEntityId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Label");
|
||||
|
||||
b.Navigation("PrivateEntity");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTablePrivateStreamingPlatform", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.PrivateEntity", "PrivateEntity")
|
||||
.WithMany("PrivateStreamingPlatforms")
|
||||
.HasForeignKey("PrivateEntityId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.SharedListEntity", null)
|
||||
.WithMany("LinkTablePrivateStreamingPlatforms")
|
||||
.HasForeignKey("SharedListEntityId");
|
||||
|
||||
b.HasOne("CouchLog.Data.StreamingPlatform", "StreamingPlatform")
|
||||
.WithMany()
|
||||
.HasForeignKey("StreamingPlatformId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("PrivateEntity");
|
||||
|
||||
b.Navigation("StreamingPlatform");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTableSharedLabel", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.SharedListEntity", "SharedListEntity")
|
||||
.WithMany("LinkTableSharedLabels")
|
||||
.HasForeignKey("SharedListEntityId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.SharedListLabel", "SharedListLabel")
|
||||
.WithMany("LinkTableSharedLabels")
|
||||
.HasForeignKey("SharedListLabelId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("SharedListEntity");
|
||||
|
||||
b.Navigation("SharedListLabel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTableSharedUser", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.SharedList", "SharedList")
|
||||
.WithMany("SharedListUsers")
|
||||
.HasForeignKey("SharedListId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.ApplicationUser", "User")
|
||||
.WithMany("LinkTableSharedUsers")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("SharedList");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.PrivateEntity", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.GlobalEntity", "GlobalEntity")
|
||||
.WithMany("PrivateEntities")
|
||||
.HasForeignKey("GlobalEntityId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.ApplicationUser", "User")
|
||||
.WithMany("PrivateEntities")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.UserWatchStatus", "UserWatchStatus")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserWatchStatusId");
|
||||
|
||||
b.Navigation("GlobalEntity");
|
||||
|
||||
b.Navigation("User");
|
||||
|
||||
b.Navigation("UserWatchStatus");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedListEntity", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.GlobalEntity", "GlobalEntity")
|
||||
.WithMany("SharedListEntities")
|
||||
.HasForeignKey("GlobalEntityId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.SharedList", "SharedList")
|
||||
.WithMany("SharedListEntities")
|
||||
.HasForeignKey("SharedListId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.SharedWatchStatus", "SharedWatchStatus")
|
||||
.WithMany("SharedListEntities")
|
||||
.HasForeignKey("SharedWatchStatusId");
|
||||
|
||||
b.Navigation("GlobalEntity");
|
||||
|
||||
b.Navigation("SharedList");
|
||||
|
||||
b.Navigation("SharedWatchStatus");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedListLabel", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.SharedList", "SharedList")
|
||||
.WithMany("SharedListLabels")
|
||||
.HasForeignKey("SharedListId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("SharedList");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedWatchStatus", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.SharedList", "SharedList")
|
||||
.WithMany("SharedWatchStatuses")
|
||||
.HasForeignKey("SharedListId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("SharedList");
|
||||
});
|
||||
|
||||
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("CouchLog.Data.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.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("CouchLog.Data.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.ApplicationUser", b =>
|
||||
{
|
||||
b.Navigation("CreatedGlobalEntities");
|
||||
|
||||
b.Navigation("CreatedLabels");
|
||||
|
||||
b.Navigation("LinkTableSharedUsers");
|
||||
|
||||
b.Navigation("PrivateEntities");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.Genre", b =>
|
||||
{
|
||||
b.Navigation("LinkTableGlobalGenres");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.GlobalEntity", b =>
|
||||
{
|
||||
b.Navigation("LinkTableGlobalGenres");
|
||||
|
||||
b.Navigation("PrivateEntities");
|
||||
|
||||
b.Navigation("SharedListEntities");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.Label", b =>
|
||||
{
|
||||
b.Navigation("LinkTablePrivateLabels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.MediaType", b =>
|
||||
{
|
||||
b.Navigation("GlobalEntities");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.PrivateEntity", b =>
|
||||
{
|
||||
b.Navigation("PrivateEntityLabels");
|
||||
|
||||
b.Navigation("PrivateStreamingPlatforms");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedList", b =>
|
||||
{
|
||||
b.Navigation("SharedListEntities");
|
||||
|
||||
b.Navigation("SharedListLabels");
|
||||
|
||||
b.Navigation("SharedListUsers");
|
||||
|
||||
b.Navigation("SharedWatchStatuses");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedListEntity", b =>
|
||||
{
|
||||
b.Navigation("LinkTablePrivateStreamingPlatforms");
|
||||
|
||||
b.Navigation("LinkTableSharedLabels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedListLabel", b =>
|
||||
{
|
||||
b.Navigation("LinkTableSharedLabels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedWatchStatus", b =>
|
||||
{
|
||||
b.Navigation("SharedListEntities");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace CouchLog.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class CouchLogState : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "CouchLogState",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
IsInitialized = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
InitializationDate = table.Column<DateTime>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_CouchLogState", x => x.Id);
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "CouchLogState");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,992 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using CouchLog.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace CouchLog.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20260103202104_AccountsSettings")]
|
||||
partial class AccountsSettings
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "10.0.1");
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.AccountsSettings", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsRegistrationAllowed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("AccountsSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.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("TEXT");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasDatabaseName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.CouchLogState", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("InitializationDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsInitialized")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CouchLogState");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.Genre", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Genres");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.GlobalEntity", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CreatorId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsPrivate")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PicturePath")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("TypeId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatorId");
|
||||
|
||||
b.HasIndex("TypeId");
|
||||
|
||||
b.ToTable("GlobalEntities");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.Label", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CreatorId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatorId");
|
||||
|
||||
b.ToTable("Labels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTableGlobalGenre", b =>
|
||||
{
|
||||
b.Property<int>("GlobalEntityId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnOrder(0);
|
||||
|
||||
b.Property<int>("GenreId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnOrder(1);
|
||||
|
||||
b.HasKey("GlobalEntityId", "GenreId");
|
||||
|
||||
b.HasIndex("GenreId");
|
||||
|
||||
b.ToTable("LinkTableGlobalGenre");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTablePrivateLabel", b =>
|
||||
{
|
||||
b.Property<int>("PrivateEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("LabelId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("PrivateEntityId", "LabelId");
|
||||
|
||||
b.HasIndex("LabelId");
|
||||
|
||||
b.ToTable("LinkTablePrivateLabel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTablePrivateStreamingPlatform", b =>
|
||||
{
|
||||
b.Property<int>("PrivateEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("StreamingPlatformId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("SharedListEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("PrivateEntityId", "StreamingPlatformId");
|
||||
|
||||
b.HasIndex("SharedListEntityId");
|
||||
|
||||
b.HasIndex("StreamingPlatformId");
|
||||
|
||||
b.ToTable("LinkTablePrivateStreamingPlatform");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTableSharedLabel", b =>
|
||||
{
|
||||
b.Property<int>("SharedListLabelId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SharedListEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("SharedListLabelId", "SharedListEntityId");
|
||||
|
||||
b.HasIndex("SharedListEntityId");
|
||||
|
||||
b.ToTable("LinkTableSharedLabel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTableSharedUser", b =>
|
||||
{
|
||||
b.Property<int>("SharedListId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("SharedListId", "UserId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("LinkTableSharedUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.MediaType", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("MediaType");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.PrivateEntity", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(1000)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("Episode")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Favorite")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("GlobalEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("Rating")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("Season")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("UserWatchStatusId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GlobalEntityId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.HasIndex("UserWatchStatusId");
|
||||
|
||||
b.ToTable("PrivateEntities");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedList", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(150)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SharedLists");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedListEntity", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(1000)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("Episode")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Favorite")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("GlobalEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("Season")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SharedListId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("SharedWatchStatusId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GlobalEntityId");
|
||||
|
||||
b.HasIndex("SharedListId");
|
||||
|
||||
b.HasIndex("SharedWatchStatusId");
|
||||
|
||||
b.ToTable("SharedListEntities");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedListLabel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("SharedListId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SharedListId");
|
||||
|
||||
b.ToTable("SharedListLabels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedWatchStatus", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ColorCode")
|
||||
.HasMaxLength(7)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("SharedListId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SharedListId");
|
||||
|
||||
b.ToTable("SharedWatchStatuses");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.StreamingPlatform", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PicturePath")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("StreamingPlatforms");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.UserWatchStatus", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ColorCode")
|
||||
.HasMaxLength(7)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("UserWatchStatuses");
|
||||
});
|
||||
|
||||
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("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
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");
|
||||
|
||||
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");
|
||||
|
||||
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("CouchLog.Data.GlobalEntity", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.ApplicationUser", "User")
|
||||
.WithMany("CreatedGlobalEntities")
|
||||
.HasForeignKey("CreatorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.MediaType", "MediaType")
|
||||
.WithMany("GlobalEntities")
|
||||
.HasForeignKey("TypeId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("MediaType");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.Label", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.ApplicationUser", "User")
|
||||
.WithMany("CreatedLabels")
|
||||
.HasForeignKey("CreatorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTableGlobalGenre", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.Genre", "Genre")
|
||||
.WithMany("LinkTableGlobalGenres")
|
||||
.HasForeignKey("GenreId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.GlobalEntity", "GlobalEntity")
|
||||
.WithMany("LinkTableGlobalGenres")
|
||||
.HasForeignKey("GlobalEntityId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Genre");
|
||||
|
||||
b.Navigation("GlobalEntity");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTablePrivateLabel", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.Label", "Label")
|
||||
.WithMany("LinkTablePrivateLabels")
|
||||
.HasForeignKey("LabelId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.PrivateEntity", "PrivateEntity")
|
||||
.WithMany("PrivateEntityLabels")
|
||||
.HasForeignKey("PrivateEntityId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Label");
|
||||
|
||||
b.Navigation("PrivateEntity");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTablePrivateStreamingPlatform", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.PrivateEntity", "PrivateEntity")
|
||||
.WithMany("PrivateStreamingPlatforms")
|
||||
.HasForeignKey("PrivateEntityId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.SharedListEntity", null)
|
||||
.WithMany("LinkTablePrivateStreamingPlatforms")
|
||||
.HasForeignKey("SharedListEntityId");
|
||||
|
||||
b.HasOne("CouchLog.Data.StreamingPlatform", "StreamingPlatform")
|
||||
.WithMany()
|
||||
.HasForeignKey("StreamingPlatformId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("PrivateEntity");
|
||||
|
||||
b.Navigation("StreamingPlatform");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTableSharedLabel", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.SharedListEntity", "SharedListEntity")
|
||||
.WithMany("LinkTableSharedLabels")
|
||||
.HasForeignKey("SharedListEntityId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.SharedListLabel", "SharedListLabel")
|
||||
.WithMany("LinkTableSharedLabels")
|
||||
.HasForeignKey("SharedListLabelId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("SharedListEntity");
|
||||
|
||||
b.Navigation("SharedListLabel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTableSharedUser", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.SharedList", "SharedList")
|
||||
.WithMany("SharedListUsers")
|
||||
.HasForeignKey("SharedListId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.ApplicationUser", "User")
|
||||
.WithMany("LinkTableSharedUsers")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("SharedList");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.PrivateEntity", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.GlobalEntity", "GlobalEntity")
|
||||
.WithMany("PrivateEntities")
|
||||
.HasForeignKey("GlobalEntityId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.ApplicationUser", "User")
|
||||
.WithMany("PrivateEntities")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.UserWatchStatus", "UserWatchStatus")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserWatchStatusId");
|
||||
|
||||
b.Navigation("GlobalEntity");
|
||||
|
||||
b.Navigation("User");
|
||||
|
||||
b.Navigation("UserWatchStatus");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedListEntity", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.GlobalEntity", "GlobalEntity")
|
||||
.WithMany("SharedListEntities")
|
||||
.HasForeignKey("GlobalEntityId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.SharedList", "SharedList")
|
||||
.WithMany("SharedListEntities")
|
||||
.HasForeignKey("SharedListId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.SharedWatchStatus", "SharedWatchStatus")
|
||||
.WithMany("SharedListEntities")
|
||||
.HasForeignKey("SharedWatchStatusId");
|
||||
|
||||
b.Navigation("GlobalEntity");
|
||||
|
||||
b.Navigation("SharedList");
|
||||
|
||||
b.Navigation("SharedWatchStatus");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedListLabel", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.SharedList", "SharedList")
|
||||
.WithMany("SharedListLabels")
|
||||
.HasForeignKey("SharedListId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("SharedList");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedWatchStatus", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.SharedList", "SharedList")
|
||||
.WithMany("SharedWatchStatuses")
|
||||
.HasForeignKey("SharedListId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("SharedList");
|
||||
});
|
||||
|
||||
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("CouchLog.Data.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.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("CouchLog.Data.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.ApplicationUser", b =>
|
||||
{
|
||||
b.Navigation("CreatedGlobalEntities");
|
||||
|
||||
b.Navigation("CreatedLabels");
|
||||
|
||||
b.Navigation("LinkTableSharedUsers");
|
||||
|
||||
b.Navigation("PrivateEntities");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.Genre", b =>
|
||||
{
|
||||
b.Navigation("LinkTableGlobalGenres");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.GlobalEntity", b =>
|
||||
{
|
||||
b.Navigation("LinkTableGlobalGenres");
|
||||
|
||||
b.Navigation("PrivateEntities");
|
||||
|
||||
b.Navigation("SharedListEntities");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.Label", b =>
|
||||
{
|
||||
b.Navigation("LinkTablePrivateLabels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.MediaType", b =>
|
||||
{
|
||||
b.Navigation("GlobalEntities");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.PrivateEntity", b =>
|
||||
{
|
||||
b.Navigation("PrivateEntityLabels");
|
||||
|
||||
b.Navigation("PrivateStreamingPlatforms");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedList", b =>
|
||||
{
|
||||
b.Navigation("SharedListEntities");
|
||||
|
||||
b.Navigation("SharedListLabels");
|
||||
|
||||
b.Navigation("SharedListUsers");
|
||||
|
||||
b.Navigation("SharedWatchStatuses");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedListEntity", b =>
|
||||
{
|
||||
b.Navigation("LinkTablePrivateStreamingPlatforms");
|
||||
|
||||
b.Navigation("LinkTableSharedLabels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedListLabel", b =>
|
||||
{
|
||||
b.Navigation("LinkTableSharedLabels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedWatchStatus", b =>
|
||||
{
|
||||
b.Navigation("SharedListEntities");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace CouchLog.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AccountsSettings : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AccountsSettings",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
IsRegistrationAllowed = table.Column<bool>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AccountsSettings", x => x.Id);
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "AccountsSettings");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,992 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using CouchLog.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace CouchLog.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20260104151950_FixAccountsSettingsKey")]
|
||||
partial class FixAccountsSettingsKey
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "10.0.1");
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.AccountsSettings", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsRegistrationAllowed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("AccountsSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.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("TEXT");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasDatabaseName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.CouchLogState", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("InitializationDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsInitialized")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CouchLogState");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.Genre", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Genres");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.GlobalEntity", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CreatorId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsPrivate")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PicturePath")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("TypeId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatorId");
|
||||
|
||||
b.HasIndex("TypeId");
|
||||
|
||||
b.ToTable("GlobalEntities");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.Label", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CreatorId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatorId");
|
||||
|
||||
b.ToTable("Labels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTableGlobalGenre", b =>
|
||||
{
|
||||
b.Property<int>("GlobalEntityId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnOrder(0);
|
||||
|
||||
b.Property<int>("GenreId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnOrder(1);
|
||||
|
||||
b.HasKey("GlobalEntityId", "GenreId");
|
||||
|
||||
b.HasIndex("GenreId");
|
||||
|
||||
b.ToTable("LinkTableGlobalGenre");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTablePrivateLabel", b =>
|
||||
{
|
||||
b.Property<int>("PrivateEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("LabelId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("PrivateEntityId", "LabelId");
|
||||
|
||||
b.HasIndex("LabelId");
|
||||
|
||||
b.ToTable("LinkTablePrivateLabel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTablePrivateStreamingPlatform", b =>
|
||||
{
|
||||
b.Property<int>("PrivateEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("StreamingPlatformId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("SharedListEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("PrivateEntityId", "StreamingPlatformId");
|
||||
|
||||
b.HasIndex("SharedListEntityId");
|
||||
|
||||
b.HasIndex("StreamingPlatformId");
|
||||
|
||||
b.ToTable("LinkTablePrivateStreamingPlatform");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTableSharedLabel", b =>
|
||||
{
|
||||
b.Property<int>("SharedListLabelId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SharedListEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("SharedListLabelId", "SharedListEntityId");
|
||||
|
||||
b.HasIndex("SharedListEntityId");
|
||||
|
||||
b.ToTable("LinkTableSharedLabel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTableSharedUser", b =>
|
||||
{
|
||||
b.Property<int>("SharedListId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("SharedListId", "UserId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("LinkTableSharedUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.MediaType", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("MediaType");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.PrivateEntity", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(1000)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("Episode")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Favorite")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("GlobalEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("Rating")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("Season")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("UserWatchStatusId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GlobalEntityId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.HasIndex("UserWatchStatusId");
|
||||
|
||||
b.ToTable("PrivateEntities");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedList", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(150)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SharedLists");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedListEntity", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(1000)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("Episode")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Favorite")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("GlobalEntityId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("Season")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SharedListId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("SharedWatchStatusId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GlobalEntityId");
|
||||
|
||||
b.HasIndex("SharedListId");
|
||||
|
||||
b.HasIndex("SharedWatchStatusId");
|
||||
|
||||
b.ToTable("SharedListEntities");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedListLabel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("SharedListId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SharedListId");
|
||||
|
||||
b.ToTable("SharedListLabels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedWatchStatus", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ColorCode")
|
||||
.HasMaxLength(7)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("SharedListId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SharedListId");
|
||||
|
||||
b.ToTable("SharedWatchStatuses");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.StreamingPlatform", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PicturePath")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("StreamingPlatforms");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.UserWatchStatus", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ColorCode")
|
||||
.HasMaxLength(7)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastChange")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("UserWatchStatuses");
|
||||
});
|
||||
|
||||
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("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
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");
|
||||
|
||||
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");
|
||||
|
||||
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("CouchLog.Data.GlobalEntity", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.ApplicationUser", "User")
|
||||
.WithMany("CreatedGlobalEntities")
|
||||
.HasForeignKey("CreatorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.MediaType", "MediaType")
|
||||
.WithMany("GlobalEntities")
|
||||
.HasForeignKey("TypeId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("MediaType");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.Label", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.ApplicationUser", "User")
|
||||
.WithMany("CreatedLabels")
|
||||
.HasForeignKey("CreatorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTableGlobalGenre", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.Genre", "Genre")
|
||||
.WithMany("LinkTableGlobalGenres")
|
||||
.HasForeignKey("GenreId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.GlobalEntity", "GlobalEntity")
|
||||
.WithMany("LinkTableGlobalGenres")
|
||||
.HasForeignKey("GlobalEntityId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Genre");
|
||||
|
||||
b.Navigation("GlobalEntity");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTablePrivateLabel", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.Label", "Label")
|
||||
.WithMany("LinkTablePrivateLabels")
|
||||
.HasForeignKey("LabelId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.PrivateEntity", "PrivateEntity")
|
||||
.WithMany("PrivateEntityLabels")
|
||||
.HasForeignKey("PrivateEntityId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Label");
|
||||
|
||||
b.Navigation("PrivateEntity");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTablePrivateStreamingPlatform", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.PrivateEntity", "PrivateEntity")
|
||||
.WithMany("PrivateStreamingPlatforms")
|
||||
.HasForeignKey("PrivateEntityId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.SharedListEntity", null)
|
||||
.WithMany("LinkTablePrivateStreamingPlatforms")
|
||||
.HasForeignKey("SharedListEntityId");
|
||||
|
||||
b.HasOne("CouchLog.Data.StreamingPlatform", "StreamingPlatform")
|
||||
.WithMany()
|
||||
.HasForeignKey("StreamingPlatformId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("PrivateEntity");
|
||||
|
||||
b.Navigation("StreamingPlatform");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTableSharedLabel", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.SharedListEntity", "SharedListEntity")
|
||||
.WithMany("LinkTableSharedLabels")
|
||||
.HasForeignKey("SharedListEntityId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.SharedListLabel", "SharedListLabel")
|
||||
.WithMany("LinkTableSharedLabels")
|
||||
.HasForeignKey("SharedListLabelId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("SharedListEntity");
|
||||
|
||||
b.Navigation("SharedListLabel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.LinkTableSharedUser", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.SharedList", "SharedList")
|
||||
.WithMany("SharedListUsers")
|
||||
.HasForeignKey("SharedListId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.ApplicationUser", "User")
|
||||
.WithMany("LinkTableSharedUsers")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("SharedList");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.PrivateEntity", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.GlobalEntity", "GlobalEntity")
|
||||
.WithMany("PrivateEntities")
|
||||
.HasForeignKey("GlobalEntityId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.ApplicationUser", "User")
|
||||
.WithMany("PrivateEntities")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.UserWatchStatus", "UserWatchStatus")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserWatchStatusId");
|
||||
|
||||
b.Navigation("GlobalEntity");
|
||||
|
||||
b.Navigation("User");
|
||||
|
||||
b.Navigation("UserWatchStatus");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedListEntity", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.GlobalEntity", "GlobalEntity")
|
||||
.WithMany("SharedListEntities")
|
||||
.HasForeignKey("GlobalEntityId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.SharedList", "SharedList")
|
||||
.WithMany("SharedListEntities")
|
||||
.HasForeignKey("SharedListId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CouchLog.Data.SharedWatchStatus", "SharedWatchStatus")
|
||||
.WithMany("SharedListEntities")
|
||||
.HasForeignKey("SharedWatchStatusId");
|
||||
|
||||
b.Navigation("GlobalEntity");
|
||||
|
||||
b.Navigation("SharedList");
|
||||
|
||||
b.Navigation("SharedWatchStatus");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedListLabel", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.SharedList", "SharedList")
|
||||
.WithMany("SharedListLabels")
|
||||
.HasForeignKey("SharedListId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("SharedList");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedWatchStatus", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.SharedList", "SharedList")
|
||||
.WithMany("SharedWatchStatuses")
|
||||
.HasForeignKey("SharedListId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("SharedList");
|
||||
});
|
||||
|
||||
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("CouchLog.Data.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.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("CouchLog.Data.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("CouchLog.Data.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.ApplicationUser", b =>
|
||||
{
|
||||
b.Navigation("CreatedGlobalEntities");
|
||||
|
||||
b.Navigation("CreatedLabels");
|
||||
|
||||
b.Navigation("LinkTableSharedUsers");
|
||||
|
||||
b.Navigation("PrivateEntities");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.Genre", b =>
|
||||
{
|
||||
b.Navigation("LinkTableGlobalGenres");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.GlobalEntity", b =>
|
||||
{
|
||||
b.Navigation("LinkTableGlobalGenres");
|
||||
|
||||
b.Navigation("PrivateEntities");
|
||||
|
||||
b.Navigation("SharedListEntities");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.Label", b =>
|
||||
{
|
||||
b.Navigation("LinkTablePrivateLabels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.MediaType", b =>
|
||||
{
|
||||
b.Navigation("GlobalEntities");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.PrivateEntity", b =>
|
||||
{
|
||||
b.Navigation("PrivateEntityLabels");
|
||||
|
||||
b.Navigation("PrivateStreamingPlatforms");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedList", b =>
|
||||
{
|
||||
b.Navigation("SharedListEntities");
|
||||
|
||||
b.Navigation("SharedListLabels");
|
||||
|
||||
b.Navigation("SharedListUsers");
|
||||
|
||||
b.Navigation("SharedWatchStatuses");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedListEntity", b =>
|
||||
{
|
||||
b.Navigation("LinkTablePrivateStreamingPlatforms");
|
||||
|
||||
b.Navigation("LinkTableSharedLabels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedListLabel", b =>
|
||||
{
|
||||
b.Navigation("LinkTableSharedLabels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.SharedWatchStatus", b =>
|
||||
{
|
||||
b.Navigation("SharedListEntities");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace CouchLog.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class FixAccountsSettingsKey : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,20 @@ namespace CouchLog.Migrations
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "10.0.1");
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.AccountsSettings", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsRegistrationAllowed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("AccountsSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.ApplicationUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
@@ -81,6 +95,23 @@ namespace CouchLog.Migrations
|
||||
b.ToTable("AspNetUsers", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.CouchLogState", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("InitializationDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsInitialized")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CouchLogState");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CouchLog.Data.Genre", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
|
||||
+75
-28
@@ -1,23 +1,52 @@
|
||||
using CouchLog.Data;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace CouchLog
|
||||
{
|
||||
public class OnStartUp
|
||||
public class OnStartUp(ApplicationDbContext CouchLogDB, RoleManager<IdentityRole> RoleManager)
|
||||
{
|
||||
private ApplicationDbContext CouchLogDB;
|
||||
private readonly ApplicationDbContext CouchLogDB = CouchLogDB;
|
||||
private readonly RoleManager<IdentityRole> RoleManager = RoleManager;
|
||||
|
||||
public OnStartUp(ApplicationDbContext CouchLogDB)
|
||||
public async Task CreateRoles()
|
||||
{
|
||||
this.CouchLogDB = CouchLogDB;
|
||||
string[] roleNames = ["Admin", "User"];
|
||||
IdentityResult roleResult;
|
||||
|
||||
foreach (var roleName in roleNames)
|
||||
{
|
||||
var roleExist = await RoleManager.RoleExistsAsync(roleName);
|
||||
if (!roleExist)
|
||||
{
|
||||
roleResult = await RoleManager.CreateAsync(new IdentityRole(roleName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddBasicDatabaseEntries()
|
||||
public async Task CreateStanardSettings()
|
||||
{
|
||||
if(!CouchLogDB.AccountsSettings.Any())
|
||||
{
|
||||
AccountsSettings accountsSettings = new()
|
||||
{
|
||||
Id = 1,
|
||||
IsRegistrationAllowed = true,
|
||||
};
|
||||
|
||||
await CouchLogDB.AccountsSettings.AddAsync(accountsSettings);
|
||||
|
||||
await CouchLogDB.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task AddBasicDatabaseEntries()
|
||||
{
|
||||
//##################
|
||||
//### MediaTypes ###
|
||||
//##################
|
||||
List<MediaType> MediaTypes = new List<MediaType>
|
||||
{
|
||||
List<MediaType> MediaTypes =
|
||||
[
|
||||
//Video based
|
||||
new() { Name="Movie" },
|
||||
new() { Name="Series" },
|
||||
@@ -38,23 +67,24 @@ namespace CouchLog
|
||||
//Text based
|
||||
new() { Name = "Book" },
|
||||
new() { Name = "Comic" },
|
||||
};
|
||||
];
|
||||
|
||||
foreach (MediaType MediaType in MediaTypes)
|
||||
{
|
||||
if(!CouchLogDB.MediaType.Any(m => m.Name == MediaType.Name))
|
||||
if(!await CouchLogDB.MediaType.AnyAsync(m => m.Name == MediaType.Name))
|
||||
{
|
||||
CouchLogDB.MediaType.Add(MediaType);
|
||||
await CouchLogDB.MediaType.AddAsync(MediaType);
|
||||
}
|
||||
}
|
||||
|
||||
//##############
|
||||
//### Genres ###
|
||||
//##############
|
||||
List<Genre> Genres = new List<Genre>
|
||||
{
|
||||
List<Genre> Genres =
|
||||
[
|
||||
new() { Name = "Action", CreationTime = DateTime.Now },
|
||||
new() { Name = "Animation", CreationTime = DateTime.Now },
|
||||
new() { Name = "Adventure", CreationTime = DateTime.Now },
|
||||
new() { Name = "Comedy", CreationTime = DateTime.Now },
|
||||
new() { Name = "Crime", CreationTime = DateTime.Now },
|
||||
new() { Name = "Drama", CreationTime = DateTime.Now },
|
||||
@@ -69,13 +99,13 @@ namespace CouchLog
|
||||
new() { Name = "Thriller", CreationTime = DateTime.Now },
|
||||
new() { Name = "War", CreationTime = DateTime.Now },
|
||||
new() { Name = "Western", CreationTime = DateTime.Now },
|
||||
};
|
||||
];
|
||||
|
||||
foreach(Genre Genre in Genres)
|
||||
{
|
||||
if(!CouchLogDB.Genres.Any(m => m.Name == Genre.Name))
|
||||
if(! await CouchLogDB.Genres.AnyAsync(m => m.Name == Genre.Name))
|
||||
{
|
||||
CouchLogDB.Genres.Add(Genre);
|
||||
await CouchLogDB.Genres.AddAsync(Genre);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,8 +113,8 @@ namespace CouchLog
|
||||
//##########################
|
||||
//### StreamingPlatforms ###
|
||||
//##########################
|
||||
List<StreamingPlatform> StreamingPlatforms = new List<StreamingPlatform>
|
||||
{
|
||||
List<StreamingPlatform> StreamingPlatforms =
|
||||
[
|
||||
new() { Name = "Netflix", PicturePath="StreamingPlatforms/Netflix.png", CreationTime = DateTime.Now },
|
||||
new() { Name = "Prime Video", PicturePath="StreamingPlatforms/Prime-Video.png", CreationTime = DateTime.Now },
|
||||
new() { Name = "Disney+", PicturePath="StreamingPlatforms/Disney+.png", CreationTime = DateTime.Now },
|
||||
@@ -92,38 +122,55 @@ namespace CouchLog
|
||||
new() { Name = "WOW TV", PicturePath="StreamingPlatforms/WOWTV.png", CreationTime = DateTime.Now },
|
||||
new() { Name = "Paramount+", PicturePath="StreamingPlatforms/Paramount+.png", CreationTime = DateTime.Now },
|
||||
new() { Name = "Joyn", PicturePath="StreamingPlatforms/Joyn.png", CreationTime = DateTime.Now },
|
||||
};
|
||||
];
|
||||
|
||||
foreach(StreamingPlatform StreamingPlatform in StreamingPlatforms)
|
||||
{
|
||||
if(!CouchLogDB.StreamingPlatforms.Any(m => m.Name == StreamingPlatform.Name))
|
||||
if(! await CouchLogDB.StreamingPlatforms.AnyAsync(m => m.Name == StreamingPlatform.Name))
|
||||
{
|
||||
CouchLogDB.StreamingPlatforms.Add(StreamingPlatform);
|
||||
await CouchLogDB.StreamingPlatforms.AddAsync(StreamingPlatform);
|
||||
}
|
||||
}
|
||||
|
||||
//##########################
|
||||
//###### WatchStates #######
|
||||
//##########################
|
||||
List<UserWatchStatus> UserWatchStatuses = new List<UserWatchStatus>
|
||||
{
|
||||
List<UserWatchStatus> UserWatchStatuses =
|
||||
[
|
||||
new() { Name = "Not watched", CreationTime = DateTime.Now },
|
||||
new() { Name = "Started", CreationTime = DateTime.Now },
|
||||
new() { Name = "Watching", CreationTime = DateTime.Now },
|
||||
new() { Name = "Finished", CreationTime = DateTime.Now },
|
||||
new() { Name = "Paused", CreationTime = DateTime.Now },
|
||||
new() { Name = "Waiting for next Season", CreationTime = DateTime.Now },
|
||||
new() { Name = "Aborted", CreationTime= DateTime.Now },
|
||||
};
|
||||
];
|
||||
|
||||
foreach(UserWatchStatus UserWatchStatus in UserWatchStatuses)
|
||||
{
|
||||
if(!CouchLogDB.UserWatchStatuses.Any(m => m.Name == UserWatchStatus.Name))
|
||||
if(! await CouchLogDB.UserWatchStatuses.AnyAsync(m => m.Name == UserWatchStatus.Name))
|
||||
{
|
||||
CouchLogDB.UserWatchStatuses.Add(UserWatchStatus);
|
||||
await CouchLogDB.UserWatchStatuses.AddAsync(UserWatchStatus);
|
||||
}
|
||||
}
|
||||
|
||||
//#################################################
|
||||
//###### Old-Things that need to be deleted #######
|
||||
//#################################################
|
||||
List<UserWatchStatus> oldUserWatchStatuses =
|
||||
[
|
||||
new() { Name = "Started" , CreationTime = DateTime.Now },
|
||||
];
|
||||
|
||||
CouchLogDB.SaveChanges();
|
||||
foreach(UserWatchStatus oldUserWatchStatus in oldUserWatchStatuses)
|
||||
{
|
||||
UserWatchStatus? toDeletedUserWatchStatus = await CouchLogDB.UserWatchStatuses.FirstOrDefaultAsync(m => m.Name == oldUserWatchStatus.Name);
|
||||
|
||||
if(toDeletedUserWatchStatus != null)
|
||||
{
|
||||
CouchLogDB.UserWatchStatuses.Remove(toDeletedUserWatchStatus);
|
||||
}
|
||||
}
|
||||
|
||||
await CouchLogDB.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-84
@@ -5,6 +5,8 @@ using CouchLog.Components;
|
||||
using CouchLog.Components.Account;
|
||||
using CouchLog.Data;
|
||||
using CouchLog;
|
||||
using MudBlazor;
|
||||
using MudBlazor.Services;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
@@ -35,6 +37,10 @@ builder.Services.AddIdentityCore<ApplicationUser>(options => options.SignIn.Requ
|
||||
.AddDefaultTokenProviders();
|
||||
|
||||
builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>();
|
||||
builder.Services.AddMudServices(config =>
|
||||
{
|
||||
config.SnackbarConfiguration.PositionClass = Defaults.Classes.Position.BottomCenter;
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
@@ -65,91 +71,12 @@ using (var scope = app.Services.CreateScope())
|
||||
var CouchLogDB = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
|
||||
CouchLogDB.Database.Migrate();
|
||||
|
||||
var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>();
|
||||
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
|
||||
var RoleManager = scope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>();
|
||||
|
||||
string[] roleNames = { "Admin", "User" };
|
||||
IdentityResult roleResult;
|
||||
|
||||
foreach (var roleName in roleNames)
|
||||
{
|
||||
var roleExist = await roleManager.RoleExistsAsync(roleName);
|
||||
if (!roleExist)
|
||||
{
|
||||
roleResult = await roleManager.CreateAsync(new IdentityRole(roleName));
|
||||
}
|
||||
}
|
||||
|
||||
var adminUsername = "Admin";
|
||||
var normalUsername = "User";
|
||||
var adminPassword = "EinSehrSicheresPasswort123!";
|
||||
|
||||
var adminUser = await userManager.FindByNameAsync(adminUsername);
|
||||
var normalUser = await userManager.FindByNameAsync(normalUsername);
|
||||
|
||||
if (adminUser == null)
|
||||
{
|
||||
adminUser = new ApplicationUser
|
||||
{
|
||||
UserName = adminUsername,
|
||||
EmailConfirmed = true
|
||||
};
|
||||
var createResult = await userManager.CreateAsync(adminUser, adminPassword);
|
||||
|
||||
if (createResult.Succeeded)
|
||||
{
|
||||
await userManager.AddToRoleAsync(adminUser, "Admin");
|
||||
}
|
||||
}
|
||||
else if (normalUser == null)
|
||||
{
|
||||
normalUser = new ApplicationUser
|
||||
{
|
||||
UserName = normalUsername,
|
||||
EmailConfirmed = true
|
||||
};
|
||||
var createResult = await userManager.CreateAsync(normalUser, adminPassword);
|
||||
|
||||
if (createResult.Succeeded)
|
||||
{
|
||||
await userManager.AddToRoleAsync(adminUser, "User");
|
||||
}
|
||||
}
|
||||
else if (!await userManager.IsInRoleAsync(normalUser, "User"))
|
||||
{
|
||||
await userManager.AddToRoleAsync(normalUser, "User");
|
||||
}
|
||||
else if (!await userManager.IsInRoleAsync(adminUser, "Admin"))
|
||||
{
|
||||
await userManager.AddToRoleAsync(adminUser, "Admin");
|
||||
}
|
||||
|
||||
MediaType mediaType = new()
|
||||
{
|
||||
Name = "Movie"
|
||||
};
|
||||
|
||||
if (!CouchLogDB.MediaType.Any())
|
||||
CouchLogDB.MediaType.Add(mediaType);
|
||||
|
||||
await CouchLogDB.SaveChangesAsync();
|
||||
|
||||
GlobalEntity globalEntity = new()
|
||||
{
|
||||
Title = "Inception",
|
||||
CreationTime = DateTime.Now,
|
||||
CreatorId = (await userManager.FindByNameAsync("Admin"))!.Id,
|
||||
TypeId = 1,
|
||||
PicturePath = "Pictures/Inception.jpg"
|
||||
};
|
||||
|
||||
if (!CouchLogDB.GlobalEntities.Any())
|
||||
CouchLogDB.GlobalEntities.Add(globalEntity);
|
||||
|
||||
await CouchLogDB.SaveChangesAsync();
|
||||
|
||||
OnStartUp onStartUp = new(CouchLogDB);
|
||||
onStartUp.AddBasicDatabaseEntries();
|
||||
OnStartUp onStartUp = new(CouchLogDB, RoleManager);
|
||||
await onStartUp.CreateRoles();
|
||||
await onStartUp.AddBasicDatabaseEntries();
|
||||
await onStartUp.CreateStanardSettings();
|
||||
}
|
||||
|
||||
app.Run();
|
||||
@@ -6,6 +6,13 @@
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
},
|
||||
"Console": {
|
||||
"FormatterName": "simple",
|
||||
"FormatterOptions": {
|
||||
"TimestampFormat": "[HH:mm:ss]",
|
||||
"SingleLine": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 410 KiB |
@@ -1,62 +0,0 @@
|
||||
html, body {
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
background: #2d2d2d;
|
||||
color: white
|
||||
}
|
||||
|
||||
a, .btn-link {
|
||||
color: #006bb7;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
border-color: #1861ac;
|
||||
}
|
||||
|
||||
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
|
||||
box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 1.1rem;
|
||||
}
|
||||
|
||||
h1:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.valid.modified:not([type=checkbox]) {
|
||||
outline: 1px solid #26b050;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
outline: 1px solid #e50000;
|
||||
}
|
||||
|
||||
.validation-message {
|
||||
color: #e50000;
|
||||
}
|
||||
|
||||
.blazor-error-boundary {
|
||||
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
|
||||
padding: 1rem 1rem 1rem 3.7rem;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.blazor-error-boundary::after {
|
||||
content: "An error has occurred."
|
||||
}
|
||||
|
||||
.darker-border-checkbox.form-check-input {
|
||||
border-color: #929292;
|
||||
}
|
||||
|
||||
.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
|
||||
color: var(--bs-secondary-color);
|
||||
text-align: end;
|
||||
}
|
||||
|
||||
.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
|
||||
text-align: start;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,597 +0,0 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v5.3.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2024 The Bootstrap Authors
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
:root,
|
||||
[data-bs-theme=light] {
|
||||
--bs-blue: #0d6efd;
|
||||
--bs-indigo: #6610f2;
|
||||
--bs-purple: #6f42c1;
|
||||
--bs-pink: #d63384;
|
||||
--bs-red: #dc3545;
|
||||
--bs-orange: #fd7e14;
|
||||
--bs-yellow: #ffc107;
|
||||
--bs-green: #198754;
|
||||
--bs-teal: #20c997;
|
||||
--bs-cyan: #0dcaf0;
|
||||
--bs-black: #000;
|
||||
--bs-white: #fff;
|
||||
--bs-gray: #6c757d;
|
||||
--bs-gray-dark: #343a40;
|
||||
--bs-gray-100: #f8f9fa;
|
||||
--bs-gray-200: #e9ecef;
|
||||
--bs-gray-300: #dee2e6;
|
||||
--bs-gray-400: #ced4da;
|
||||
--bs-gray-500: #adb5bd;
|
||||
--bs-gray-600: #6c757d;
|
||||
--bs-gray-700: #495057;
|
||||
--bs-gray-800: #343a40;
|
||||
--bs-gray-900: #212529;
|
||||
--bs-primary: #0d6efd;
|
||||
--bs-secondary: #6c757d;
|
||||
--bs-success: #198754;
|
||||
--bs-info: #0dcaf0;
|
||||
--bs-warning: #ffc107;
|
||||
--bs-danger: #dc3545;
|
||||
--bs-light: #f8f9fa;
|
||||
--bs-dark: #212529;
|
||||
--bs-primary-rgb: 13, 110, 253;
|
||||
--bs-secondary-rgb: 108, 117, 125;
|
||||
--bs-success-rgb: 25, 135, 84;
|
||||
--bs-info-rgb: 13, 202, 240;
|
||||
--bs-warning-rgb: 255, 193, 7;
|
||||
--bs-danger-rgb: 220, 53, 69;
|
||||
--bs-light-rgb: 248, 249, 250;
|
||||
--bs-dark-rgb: 33, 37, 41;
|
||||
--bs-primary-text-emphasis: #052c65;
|
||||
--bs-secondary-text-emphasis: #2b2f32;
|
||||
--bs-success-text-emphasis: #0a3622;
|
||||
--bs-info-text-emphasis: #055160;
|
||||
--bs-warning-text-emphasis: #664d03;
|
||||
--bs-danger-text-emphasis: #58151c;
|
||||
--bs-light-text-emphasis: #495057;
|
||||
--bs-dark-text-emphasis: #495057;
|
||||
--bs-primary-bg-subtle: #cfe2ff;
|
||||
--bs-secondary-bg-subtle: #e2e3e5;
|
||||
--bs-success-bg-subtle: #d1e7dd;
|
||||
--bs-info-bg-subtle: #cff4fc;
|
||||
--bs-warning-bg-subtle: #fff3cd;
|
||||
--bs-danger-bg-subtle: #f8d7da;
|
||||
--bs-light-bg-subtle: #fcfcfd;
|
||||
--bs-dark-bg-subtle: #ced4da;
|
||||
--bs-primary-border-subtle: #9ec5fe;
|
||||
--bs-secondary-border-subtle: #c4c8cb;
|
||||
--bs-success-border-subtle: #a3cfbb;
|
||||
--bs-info-border-subtle: #9eeaf9;
|
||||
--bs-warning-border-subtle: #ffe69c;
|
||||
--bs-danger-border-subtle: #f1aeb5;
|
||||
--bs-light-border-subtle: #e9ecef;
|
||||
--bs-dark-border-subtle: #adb5bd;
|
||||
--bs-white-rgb: 255, 255, 255;
|
||||
--bs-black-rgb: 0, 0, 0;
|
||||
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
|
||||
--bs-body-font-family: var(--bs-font-sans-serif);
|
||||
--bs-body-font-size: 1rem;
|
||||
--bs-body-font-weight: 400;
|
||||
--bs-body-line-height: 1.5;
|
||||
--bs-body-color: #212529;
|
||||
--bs-body-color-rgb: 33, 37, 41;
|
||||
--bs-body-bg: #fff;
|
||||
--bs-body-bg-rgb: 255, 255, 255;
|
||||
--bs-emphasis-color: #000;
|
||||
--bs-emphasis-color-rgb: 0, 0, 0;
|
||||
--bs-secondary-color: rgba(33, 37, 41, 0.75);
|
||||
--bs-secondary-color-rgb: 33, 37, 41;
|
||||
--bs-secondary-bg: #e9ecef;
|
||||
--bs-secondary-bg-rgb: 233, 236, 239;
|
||||
--bs-tertiary-color: rgba(33, 37, 41, 0.5);
|
||||
--bs-tertiary-color-rgb: 33, 37, 41;
|
||||
--bs-tertiary-bg: #f8f9fa;
|
||||
--bs-tertiary-bg-rgb: 248, 249, 250;
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: #0d6efd;
|
||||
--bs-link-color-rgb: 13, 110, 253;
|
||||
--bs-link-decoration: underline;
|
||||
--bs-link-hover-color: #0a58ca;
|
||||
--bs-link-hover-color-rgb: 10, 88, 202;
|
||||
--bs-code-color: #d63384;
|
||||
--bs-highlight-color: #212529;
|
||||
--bs-highlight-bg: #fff3cd;
|
||||
--bs-border-width: 1px;
|
||||
--bs-border-style: solid;
|
||||
--bs-border-color: #dee2e6;
|
||||
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
|
||||
--bs-border-radius: 0.375rem;
|
||||
--bs-border-radius-sm: 0.25rem;
|
||||
--bs-border-radius-lg: 0.5rem;
|
||||
--bs-border-radius-xl: 1rem;
|
||||
--bs-border-radius-xxl: 2rem;
|
||||
--bs-border-radius-2xl: var(--bs-border-radius-xxl);
|
||||
--bs-border-radius-pill: 50rem;
|
||||
--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
||||
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
||||
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
|
||||
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
--bs-focus-ring-width: 0.25rem;
|
||||
--bs-focus-ring-opacity: 0.25;
|
||||
--bs-focus-ring-color: rgba(13, 110, 253, 0.25);
|
||||
--bs-form-valid-color: #198754;
|
||||
--bs-form-valid-border-color: #198754;
|
||||
--bs-form-invalid-color: #dc3545;
|
||||
--bs-form-invalid-border-color: #dc3545;
|
||||
}
|
||||
|
||||
[data-bs-theme=dark] {
|
||||
color-scheme: dark;
|
||||
--bs-body-color: #dee2e6;
|
||||
--bs-body-color-rgb: 222, 226, 230;
|
||||
--bs-body-bg: #212529;
|
||||
--bs-body-bg-rgb: 33, 37, 41;
|
||||
--bs-emphasis-color: #fff;
|
||||
--bs-emphasis-color-rgb: 255, 255, 255;
|
||||
--bs-secondary-color: rgba(222, 226, 230, 0.75);
|
||||
--bs-secondary-color-rgb: 222, 226, 230;
|
||||
--bs-secondary-bg: #343a40;
|
||||
--bs-secondary-bg-rgb: 52, 58, 64;
|
||||
--bs-tertiary-color: rgba(222, 226, 230, 0.5);
|
||||
--bs-tertiary-color-rgb: 222, 226, 230;
|
||||
--bs-tertiary-bg: #2b3035;
|
||||
--bs-tertiary-bg-rgb: 43, 48, 53;
|
||||
--bs-primary-text-emphasis: #6ea8fe;
|
||||
--bs-secondary-text-emphasis: #a7acb1;
|
||||
--bs-success-text-emphasis: #75b798;
|
||||
--bs-info-text-emphasis: #6edff6;
|
||||
--bs-warning-text-emphasis: #ffda6a;
|
||||
--bs-danger-text-emphasis: #ea868f;
|
||||
--bs-light-text-emphasis: #f8f9fa;
|
||||
--bs-dark-text-emphasis: #dee2e6;
|
||||
--bs-primary-bg-subtle: #031633;
|
||||
--bs-secondary-bg-subtle: #161719;
|
||||
--bs-success-bg-subtle: #051b11;
|
||||
--bs-info-bg-subtle: #032830;
|
||||
--bs-warning-bg-subtle: #332701;
|
||||
--bs-danger-bg-subtle: #2c0b0e;
|
||||
--bs-light-bg-subtle: #343a40;
|
||||
--bs-dark-bg-subtle: #1a1d20;
|
||||
--bs-primary-border-subtle: #084298;
|
||||
--bs-secondary-border-subtle: #41464b;
|
||||
--bs-success-border-subtle: #0f5132;
|
||||
--bs-info-border-subtle: #087990;
|
||||
--bs-warning-border-subtle: #997404;
|
||||
--bs-danger-border-subtle: #842029;
|
||||
--bs-light-border-subtle: #495057;
|
||||
--bs-dark-border-subtle: #343a40;
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: #6ea8fe;
|
||||
--bs-link-hover-color: #8bb9fe;
|
||||
--bs-link-color-rgb: 110, 168, 254;
|
||||
--bs-link-hover-color-rgb: 139, 185, 254;
|
||||
--bs-code-color: #e685b5;
|
||||
--bs-highlight-color: #dee2e6;
|
||||
--bs-highlight-bg: #664d03;
|
||||
--bs-border-color: #495057;
|
||||
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
|
||||
--bs-form-valid-color: #75b798;
|
||||
--bs-form-valid-border-color: #75b798;
|
||||
--bs-form-invalid-color: #ea868f;
|
||||
--bs-form-invalid-border-color: #ea868f;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
:root {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--bs-body-font-family);
|
||||
font-size: var(--bs-body-font-size);
|
||||
font-weight: var(--bs-body-font-weight);
|
||||
line-height: var(--bs-body-line-height);
|
||||
color: var(--bs-body-color);
|
||||
text-align: var(--bs-body-text-align);
|
||||
background-color: var(--bs-body-bg);
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
color: inherit;
|
||||
border: 0;
|
||||
border-top: var(--bs-border-width) solid;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
h6, h5, h4, h3, h2, h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
color: var(--bs-heading-color);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: calc(1.375rem + 1.5vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: calc(1.325rem + 0.9vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: calc(1.3rem + 0.6vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h3 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h4 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
mark {
|
||||
padding: 0.1875em;
|
||||
color: var(--bs-highlight-color);
|
||||
background-color: var(--bs-highlight-bg);
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 0.75em;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:hover {
|
||||
--bs-link-color-rgb: var(--bs-link-hover-color-rgb);
|
||||
}
|
||||
|
||||
a:not([href]):not([class]), a:not([href]):not([class]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: var(--bs-font-monospace);
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
pre code {
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-code-color);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
a > code {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
kbd {
|
||||
padding: 0.1875rem 0.375rem;
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-body-bg);
|
||||
background-color: var(--bs-body-color);
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
kbd kbd {
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img,
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
color: var(--bs-secondary-color);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
|
||||
thead,
|
||||
tbody,
|
||||
tfoot,
|
||||
tr,
|
||||
td,
|
||||
th {
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus:not(:focus-visible) {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
[role=button] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
select:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
button,
|
||||
[type=button],
|
||||
[type=reset],
|
||||
[type=submit] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
button:not(:disabled),
|
||||
[type=button]:not(:disabled),
|
||||
[type=reset]:not(:disabled),
|
||||
[type=submit]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
float: left;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
line-height: inherit;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
legend {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
legend + * {
|
||||
clear: left;
|
||||
}
|
||||
|
||||
::-webkit-datetime-edit-fields-wrapper,
|
||||
::-webkit-datetime-edit-text,
|
||||
::-webkit-datetime-edit-minute,
|
||||
::-webkit-datetime-edit-hour-field,
|
||||
::-webkit-datetime-edit-day-field,
|
||||
::-webkit-datetime-edit-month-field,
|
||||
::-webkit-datetime-edit-year-field {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-inner-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
/* rtl:raw:
|
||||
[type="tel"],
|
||||
[type="url"],
|
||||
[type="email"],
|
||||
[type="number"] {
|
||||
direction: ltr;
|
||||
}
|
||||
*/
|
||||
::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
::file-selector-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,594 +0,0 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v5.3.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2024 The Bootstrap Authors
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
:root,
|
||||
[data-bs-theme=light] {
|
||||
--bs-blue: #0d6efd;
|
||||
--bs-indigo: #6610f2;
|
||||
--bs-purple: #6f42c1;
|
||||
--bs-pink: #d63384;
|
||||
--bs-red: #dc3545;
|
||||
--bs-orange: #fd7e14;
|
||||
--bs-yellow: #ffc107;
|
||||
--bs-green: #198754;
|
||||
--bs-teal: #20c997;
|
||||
--bs-cyan: #0dcaf0;
|
||||
--bs-black: #000;
|
||||
--bs-white: #fff;
|
||||
--bs-gray: #6c757d;
|
||||
--bs-gray-dark: #343a40;
|
||||
--bs-gray-100: #f8f9fa;
|
||||
--bs-gray-200: #e9ecef;
|
||||
--bs-gray-300: #dee2e6;
|
||||
--bs-gray-400: #ced4da;
|
||||
--bs-gray-500: #adb5bd;
|
||||
--bs-gray-600: #6c757d;
|
||||
--bs-gray-700: #495057;
|
||||
--bs-gray-800: #343a40;
|
||||
--bs-gray-900: #212529;
|
||||
--bs-primary: #0d6efd;
|
||||
--bs-secondary: #6c757d;
|
||||
--bs-success: #198754;
|
||||
--bs-info: #0dcaf0;
|
||||
--bs-warning: #ffc107;
|
||||
--bs-danger: #dc3545;
|
||||
--bs-light: #f8f9fa;
|
||||
--bs-dark: #212529;
|
||||
--bs-primary-rgb: 13, 110, 253;
|
||||
--bs-secondary-rgb: 108, 117, 125;
|
||||
--bs-success-rgb: 25, 135, 84;
|
||||
--bs-info-rgb: 13, 202, 240;
|
||||
--bs-warning-rgb: 255, 193, 7;
|
||||
--bs-danger-rgb: 220, 53, 69;
|
||||
--bs-light-rgb: 248, 249, 250;
|
||||
--bs-dark-rgb: 33, 37, 41;
|
||||
--bs-primary-text-emphasis: #052c65;
|
||||
--bs-secondary-text-emphasis: #2b2f32;
|
||||
--bs-success-text-emphasis: #0a3622;
|
||||
--bs-info-text-emphasis: #055160;
|
||||
--bs-warning-text-emphasis: #664d03;
|
||||
--bs-danger-text-emphasis: #58151c;
|
||||
--bs-light-text-emphasis: #495057;
|
||||
--bs-dark-text-emphasis: #495057;
|
||||
--bs-primary-bg-subtle: #cfe2ff;
|
||||
--bs-secondary-bg-subtle: #e2e3e5;
|
||||
--bs-success-bg-subtle: #d1e7dd;
|
||||
--bs-info-bg-subtle: #cff4fc;
|
||||
--bs-warning-bg-subtle: #fff3cd;
|
||||
--bs-danger-bg-subtle: #f8d7da;
|
||||
--bs-light-bg-subtle: #fcfcfd;
|
||||
--bs-dark-bg-subtle: #ced4da;
|
||||
--bs-primary-border-subtle: #9ec5fe;
|
||||
--bs-secondary-border-subtle: #c4c8cb;
|
||||
--bs-success-border-subtle: #a3cfbb;
|
||||
--bs-info-border-subtle: #9eeaf9;
|
||||
--bs-warning-border-subtle: #ffe69c;
|
||||
--bs-danger-border-subtle: #f1aeb5;
|
||||
--bs-light-border-subtle: #e9ecef;
|
||||
--bs-dark-border-subtle: #adb5bd;
|
||||
--bs-white-rgb: 255, 255, 255;
|
||||
--bs-black-rgb: 0, 0, 0;
|
||||
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
|
||||
--bs-body-font-family: var(--bs-font-sans-serif);
|
||||
--bs-body-font-size: 1rem;
|
||||
--bs-body-font-weight: 400;
|
||||
--bs-body-line-height: 1.5;
|
||||
--bs-body-color: #212529;
|
||||
--bs-body-color-rgb: 33, 37, 41;
|
||||
--bs-body-bg: #fff;
|
||||
--bs-body-bg-rgb: 255, 255, 255;
|
||||
--bs-emphasis-color: #000;
|
||||
--bs-emphasis-color-rgb: 0, 0, 0;
|
||||
--bs-secondary-color: rgba(33, 37, 41, 0.75);
|
||||
--bs-secondary-color-rgb: 33, 37, 41;
|
||||
--bs-secondary-bg: #e9ecef;
|
||||
--bs-secondary-bg-rgb: 233, 236, 239;
|
||||
--bs-tertiary-color: rgba(33, 37, 41, 0.5);
|
||||
--bs-tertiary-color-rgb: 33, 37, 41;
|
||||
--bs-tertiary-bg: #f8f9fa;
|
||||
--bs-tertiary-bg-rgb: 248, 249, 250;
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: #0d6efd;
|
||||
--bs-link-color-rgb: 13, 110, 253;
|
||||
--bs-link-decoration: underline;
|
||||
--bs-link-hover-color: #0a58ca;
|
||||
--bs-link-hover-color-rgb: 10, 88, 202;
|
||||
--bs-code-color: #d63384;
|
||||
--bs-highlight-color: #212529;
|
||||
--bs-highlight-bg: #fff3cd;
|
||||
--bs-border-width: 1px;
|
||||
--bs-border-style: solid;
|
||||
--bs-border-color: #dee2e6;
|
||||
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
|
||||
--bs-border-radius: 0.375rem;
|
||||
--bs-border-radius-sm: 0.25rem;
|
||||
--bs-border-radius-lg: 0.5rem;
|
||||
--bs-border-radius-xl: 1rem;
|
||||
--bs-border-radius-xxl: 2rem;
|
||||
--bs-border-radius-2xl: var(--bs-border-radius-xxl);
|
||||
--bs-border-radius-pill: 50rem;
|
||||
--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
||||
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
||||
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
|
||||
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
--bs-focus-ring-width: 0.25rem;
|
||||
--bs-focus-ring-opacity: 0.25;
|
||||
--bs-focus-ring-color: rgba(13, 110, 253, 0.25);
|
||||
--bs-form-valid-color: #198754;
|
||||
--bs-form-valid-border-color: #198754;
|
||||
--bs-form-invalid-color: #dc3545;
|
||||
--bs-form-invalid-border-color: #dc3545;
|
||||
}
|
||||
|
||||
[data-bs-theme=dark] {
|
||||
color-scheme: dark;
|
||||
--bs-body-color: #dee2e6;
|
||||
--bs-body-color-rgb: 222, 226, 230;
|
||||
--bs-body-bg: #212529;
|
||||
--bs-body-bg-rgb: 33, 37, 41;
|
||||
--bs-emphasis-color: #fff;
|
||||
--bs-emphasis-color-rgb: 255, 255, 255;
|
||||
--bs-secondary-color: rgba(222, 226, 230, 0.75);
|
||||
--bs-secondary-color-rgb: 222, 226, 230;
|
||||
--bs-secondary-bg: #343a40;
|
||||
--bs-secondary-bg-rgb: 52, 58, 64;
|
||||
--bs-tertiary-color: rgba(222, 226, 230, 0.5);
|
||||
--bs-tertiary-color-rgb: 222, 226, 230;
|
||||
--bs-tertiary-bg: #2b3035;
|
||||
--bs-tertiary-bg-rgb: 43, 48, 53;
|
||||
--bs-primary-text-emphasis: #6ea8fe;
|
||||
--bs-secondary-text-emphasis: #a7acb1;
|
||||
--bs-success-text-emphasis: #75b798;
|
||||
--bs-info-text-emphasis: #6edff6;
|
||||
--bs-warning-text-emphasis: #ffda6a;
|
||||
--bs-danger-text-emphasis: #ea868f;
|
||||
--bs-light-text-emphasis: #f8f9fa;
|
||||
--bs-dark-text-emphasis: #dee2e6;
|
||||
--bs-primary-bg-subtle: #031633;
|
||||
--bs-secondary-bg-subtle: #161719;
|
||||
--bs-success-bg-subtle: #051b11;
|
||||
--bs-info-bg-subtle: #032830;
|
||||
--bs-warning-bg-subtle: #332701;
|
||||
--bs-danger-bg-subtle: #2c0b0e;
|
||||
--bs-light-bg-subtle: #343a40;
|
||||
--bs-dark-bg-subtle: #1a1d20;
|
||||
--bs-primary-border-subtle: #084298;
|
||||
--bs-secondary-border-subtle: #41464b;
|
||||
--bs-success-border-subtle: #0f5132;
|
||||
--bs-info-border-subtle: #087990;
|
||||
--bs-warning-border-subtle: #997404;
|
||||
--bs-danger-border-subtle: #842029;
|
||||
--bs-light-border-subtle: #495057;
|
||||
--bs-dark-border-subtle: #343a40;
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: #6ea8fe;
|
||||
--bs-link-hover-color: #8bb9fe;
|
||||
--bs-link-color-rgb: 110, 168, 254;
|
||||
--bs-link-hover-color-rgb: 139, 185, 254;
|
||||
--bs-code-color: #e685b5;
|
||||
--bs-highlight-color: #dee2e6;
|
||||
--bs-highlight-bg: #664d03;
|
||||
--bs-border-color: #495057;
|
||||
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
|
||||
--bs-form-valid-color: #75b798;
|
||||
--bs-form-valid-border-color: #75b798;
|
||||
--bs-form-invalid-color: #ea868f;
|
||||
--bs-form-invalid-border-color: #ea868f;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
:root {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--bs-body-font-family);
|
||||
font-size: var(--bs-body-font-size);
|
||||
font-weight: var(--bs-body-font-weight);
|
||||
line-height: var(--bs-body-line-height);
|
||||
color: var(--bs-body-color);
|
||||
text-align: var(--bs-body-text-align);
|
||||
background-color: var(--bs-body-bg);
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
color: inherit;
|
||||
border: 0;
|
||||
border-top: var(--bs-border-width) solid;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
h6, h5, h4, h3, h2, h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
color: var(--bs-heading-color);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: calc(1.375rem + 1.5vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: calc(1.325rem + 0.9vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: calc(1.3rem + 0.6vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h3 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h4 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
mark {
|
||||
padding: 0.1875em;
|
||||
color: var(--bs-highlight-color);
|
||||
background-color: var(--bs-highlight-bg);
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 0.75em;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:hover {
|
||||
--bs-link-color-rgb: var(--bs-link-hover-color-rgb);
|
||||
}
|
||||
|
||||
a:not([href]):not([class]), a:not([href]):not([class]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: var(--bs-font-monospace);
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
pre code {
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-code-color);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
a > code {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
kbd {
|
||||
padding: 0.1875rem 0.375rem;
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-body-bg);
|
||||
background-color: var(--bs-body-color);
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
kbd kbd {
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img,
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
color: var(--bs-secondary-color);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
|
||||
thead,
|
||||
tbody,
|
||||
tfoot,
|
||||
tr,
|
||||
td,
|
||||
th {
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus:not(:focus-visible) {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
[role=button] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
select:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
button,
|
||||
[type=button],
|
||||
[type=reset],
|
||||
[type=submit] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
button:not(:disabled),
|
||||
[type=button]:not(:disabled),
|
||||
[type=reset]:not(:disabled),
|
||||
[type=submit]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
float: right;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
line-height: inherit;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
legend {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
legend + * {
|
||||
clear: right;
|
||||
}
|
||||
|
||||
::-webkit-datetime-edit-fields-wrapper,
|
||||
::-webkit-datetime-edit-text,
|
||||
::-webkit-datetime-edit-minute,
|
||||
::-webkit-datetime-edit-hour-field,
|
||||
::-webkit-datetime-edit-day-field,
|
||||
::-webkit-datetime-edit-month-field,
|
||||
::-webkit-datetime-edit-year-field {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-inner-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
[type="tel"],
|
||||
[type="url"],
|
||||
[type="email"],
|
||||
[type="number"] {
|
||||
direction: ltr;
|
||||
}
|
||||
::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
::file-selector-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-12057
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-12030
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user