This commit is contained in:
2025-11-19 00:08:07 +01:00
11 changed files with 199 additions and 28 deletions

View File

@@ -9,6 +9,7 @@
@inject ApplicationDbContext CouchLogDB @inject ApplicationDbContext CouchLogDB
@inject UserManager<ApplicationUser> UserManager @inject UserManager<ApplicationUser> UserManager
@inject AuthenticationStateProvider AuthenticationStateProvider @inject AuthenticationStateProvider AuthenticationStateProvider
@inject NavigationManager NavigationManager
@attribute [Authorize] @attribute [Authorize]
@@ -17,29 +18,44 @@
<div class="container-fluid mt-4"> <div class="container-fluid mt-4">
<div class="d-flex justify-content-between align-items-center mb-4"> <div class="d-flex justify-content-between align-items-center mb-4">
<h2>Global List</h2> <h2>Global List</h2>
<button class="btn btn-primary" type="button" @onclick="ToogleCollapseNewGlobalEntity">@(isCollapseNewGlobalEntityOpen ? "X" : "Add Entity")</button> <button class="btn btn-info" type="button" @onclick="ToogleCollapseNewGlobalEntity">@(isCollapseNewGlobalEntityOpen ? "X" : "Add Entity")</button>
</div> </div>
<div class="collapse @(isCollapseNewGlobalEntityOpen ? "show" : "")" id="CollapseCreateNewGlobalEntity"> <div class="collapse @(isCollapseNewGlobalEntityOpen ? "show" : "")" id="CollapseCreateNewGlobalEntity">
<div class="mb-4 align-items-center CreateNewGlobalEntity-Container"> <div class="mb-4 align-items-center CreateNewGlobalEntity-Container">
<EditForm Model="@GlobalEntity" OnSubmit="CreateNewGlobalEntity" FormName="CreateNewGlobalEntityForm"> <EditForm Model="@GlobalEntity" OnSubmit="CreateNewGlobalEntity" FormName="CreateNewGlobalEntityForm">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="mb-3"> <div class="mb-3">
<label for="Title" class="form-label">Title</label> <label for="Title" class="form-label">Title</label>
<InputText id="Title" class="form-control" @bind-Value="GlobalEntity.Title"></InputText> <InputText id="Title" class="form-control" @bind-Value="GlobalEntity.Title"></InputText>
<ValidationMessage For="@(() => GlobalEntity.Title)"></ValidationMessage> <ValidationMessage For="@(() => GlobalEntity.Title)"></ValidationMessage>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="Type" class="form-label">Type</label> <label for="Type" class="form-label">Type</label>
<select> <select id="Type" class="form-select" @bind="SelectedMediaTypeId">
@foreach(MediaType Type in MediaTypes) @foreach(MediaType Type in MediaTypes)
{ {
<option value="@Type.Id">@Type.Name</option> <option value="@Type.Id">@Type.Name</option>
} }
</select> </select>
</div> </div>
<div class="mb-3">
<button type="submit">Create new Global Entity</button> <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>
<button type="submit" class="btn-success btn">Create new Global Entity</button>
</EditForm> </EditForm>
</div> </div>
</div> </div>
@@ -48,6 +64,29 @@
{ {
<div name="Enity-Container" class="col-12 col-md-6 col-lg-3 mb-4 Entity-Container"> <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 name="Entity-Container-Card" class="Entity-Container-Card">
<div class="Entity-Container-Menu-Button">
<button type="button" class="Entity-Container-Menu-Button" data-bs-toogle="modal" data-bs-target="@Entity.Id">&#8942;</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=""> <div name="Enity-Container-Image" class="">
<a href="javascript:void(0)" class="Entity-Container-Image"> <a href="javascript:void(0)" class="Entity-Container-Image">
<img src="@Entity.PicturePath" alt="" class="Entity-Container-Image" /> <img src="@Entity.PicturePath" alt="" class="Entity-Container-Image" />
@@ -57,10 +96,10 @@
<h3 class="">@Entity.Title</h3> <h3 class="">@Entity.Title</h3>
</div> </div>
<div name="Entity-Container-Button" class="d-flex Entity-Container-Button" style="gap: 10px;"> <div name="Entity-Container-Button" class="d-flex Entity-Container-Button" style="gap: 10px;">
<button class="btn btn-primary" type="button" @onclick="() => AddToPrivateList(Entity)"> <button class="btn btn-info" type="button" @onclick="() => AddToPrivateList(Entity)">
@(IsInPrivateList(Entity.Id) ? "Added" : "Add to Private List") @(IsInPrivateList(Entity.Id) ? "Added" : "Add to Private List")
</button> </button>
<button class="btn btn-primary" type="button">Add to Shared List</button> <button class="btn btn-info" type="button" @onclick="() => throw new NotImplementedException()">Add to Shared List</button>
</div> </div>
</div> </div>
</div> </div>
@@ -71,18 +110,33 @@
@code @code
{ {
private List<MediaType> MediaTypes = new List<MediaType>(); private List<MediaType> MediaTypes = new List<MediaType>();
public List<GlobalEntity> GlobalEntities = new List<GlobalEntity>(); 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 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;
/// <summary>
///
/// </summary>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
GlobalEntities = await CouchLogDB.GlobalEntities.OrderByDescending(Entity => Entity.Id).ToListAsync(); GlobalEntities = await CouchLogDB.GlobalEntities.OrderByDescending(Entity => Entity.Id).ToListAsync();
MediaTypes = await CouchLogDB.MediaType.OrderByDescending(Type => Type.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(); var AuthState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
var User = AuthState.User; User = AuthState.User;
var AppUser = await UserManager.GetUserAsync(User); AppUser = await UserManager.GetUserAsync(User);
if (AppUser == null) if (AppUser == null)
{ {
@@ -97,41 +151,102 @@
UserPrivateEntityIds = TempUserPrivateEntityIds.ToHashSet(); 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);
private bool isCollapseNewGlobalEntityOpen = false; //string Base64 = Convert.ToBase64String(Buffer);
//ImagePreviewUrl = $"data:{Picture.ContentType};base64,{Base64}";
}
/// <summary>
///
/// </summary>
private void ToogleCollapseNewGlobalEntity() private void ToogleCollapseNewGlobalEntity()
{ {
isCollapseNewGlobalEntityOpen = !isCollapseNewGlobalEntityOpen; isCollapseNewGlobalEntityOpen = !isCollapseNewGlobalEntityOpen;
StateHasChanged();
} }
private GlobalEntity GlobalEntity = new(); /// <summary>
///
/// </summary>
private void CreateNewGlobalEntity() /// <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;
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) private bool IsInPrivateList(int GolbalEntityId)
{ {
return UserPrivateEntityIds.Contains(GolbalEntityId); return UserPrivateEntityIds.Contains(GolbalEntityId);
} }
/// <summary>
///
/// </summary>
/// <param name="GlobalEntity"></param>
/// <returns></returns>
private async Task AddToPrivateList(GlobalEntity GlobalEntity) private async Task AddToPrivateList(GlobalEntity GlobalEntity)
{ {
var AuthState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
var User = AuthState.User;
if(User.Identity?.IsAuthenticated == true) if(User.Identity?.IsAuthenticated == true)
{ {
//var AppUser = await UserManager.GetUserAsync(User);
if(!IsInPrivateList(GlobalEntity.Id)) if(!IsInPrivateList(GlobalEntity.Id))
{ {
if (AppUser is null)
{
throw new InvalidOperationException("User not loaded or not logged in.");
}
PrivateEntity PrivateEntity = new() PrivateEntity PrivateEntity = new()
{ {
UserId = (await UserManager.GetUserAsync(User))!.Id, UserId = AppUser.Id,
CreationTime = DateTime.Now, CreationTime = DateTime.Now,
GlobalEntityId = GlobalEntity.Id, GlobalEntityId = GlobalEntity.Id,
}; };
@@ -144,4 +259,12 @@
} }
} }
} }
private void AddGenreToList(int GenreId)
{
if (!GenreIds.Contains(GenreId))
{
GenreIds.Add(GenreId);
}
}
} }

View File

@@ -7,9 +7,9 @@
color:aliceblue color:aliceblue
} }
.Entity-Container:hover { .Entity-Container:hover {
color: rgba(0,255,255,0.5); color: rgba(0,255,255,0.5);
} }
.Entity-Container-Card { .Entity-Container-Card {
position: relative; position: relative;
@@ -74,4 +74,15 @@
.CreateNewGlobalEntity-Container { .CreateNewGlobalEntity-Container {
background: #111; background: #111;
border-radius: 15px; 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;
} }

View File

@@ -4,6 +4,9 @@
<TargetFramework>net10.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<OutputType>Exe</OutputType>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<PackAsTool>True</PackAsTool>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

Binary file not shown.

View File

@@ -10,7 +10,7 @@ namespace CouchLog.Data
[Key] [Key]
public int Id { get; set; } public int Id { get; set; }
[Required] [Required (ErrorMessage = "Title is required")]
[MaxLength(200)] [MaxLength(200)]
public required string Title { get; set; } public required string Title { get; set; }

View File

@@ -11,6 +11,38 @@ namespace CouchLog
this.CouchLogDB = CouchLogDB; this.CouchLogDB = CouchLogDB;
} }
public void AddBasicGenresToDatabase()
{
List<Genre> ExistingGenres = CouchLogDB.Genres.OrderByDescending(Genre => Genre.Id).ToList();
List<Genre> Genres = new List<Genre>
{
new() { Name = "Action", CreationTime = DateTime.Now },
new() { Name = "Animation", CreationTime = DateTime.Now },
new() { Name = "Comedy", CreationTime = DateTime.Now },
new() { Name = "Crime", CreationTime = DateTime.Now },
new() { Name = "Drama", CreationTime = DateTime.Now },
new() { Name = "Fantasy", CreationTime = DateTime.Now },
new() { Name = "History", CreationTime = DateTime.Now },
new() { Name = "Horror", CreationTime = DateTime.Now },
new() { Name = "Musical", CreationTime = DateTime.Now },
new() { Name = "Miniseries", CreationTime = DateTime.Now },
new() { Name = "Mystery", CreationTime = DateTime.Now },
new() { Name = "Romance", CreationTime = DateTime.Now },
new() { Name = "Science Fiction", CreationTime = DateTime.Now },
new() { Name = "Thriller", CreationTime = DateTime.Now },
new() { Name = "War", CreationTime = DateTime.Now },
new() { Name = "Western", CreationTime = DateTime.Now },
};
foreach (Genre Genre in Genres)
{
CouchLogDB.Add(Genre);
}
CouchLogDB.SaveChangesAsync();
}
public void AddBasicDatabaseEntries() public void AddBasicDatabaseEntries()
{ {
//################## //##################

View File

@@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore;
using CouchLog.Components; using CouchLog.Components;
using CouchLog.Components.Account; using CouchLog.Components.Account;
using CouchLog.Data; using CouchLog.Data;
using CouchLog;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
@@ -145,8 +146,9 @@ using (var scope = app.Services.CreateScope())
await CouchLogDB.SaveChangesAsync(); await CouchLogDB.SaveChangesAsync();
//OnStartUp onStartUp = new(CouchLogDB);
//onStartUp.AddBasicGenresToDatabase();
} }
Console.WriteLine("ALL UP");
app.Run(); app.Run();

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB