Added missing localization, fixed missing order name

This commit is contained in:
2025-11-29 23:20:18 +01:00
parent f930d9e408
commit db8f2fcdf1
14 changed files with 548 additions and 32 deletions

View File

@@ -5,11 +5,11 @@ using Microsoft.AspNetCore.Mvc;
namespace OneForMe.Controllers;
[Route("[controller]")]
public class AuthViewController : Controller
public class AccountController : Controller
{
private readonly SignInManager<IdentityUser> _signInManager;
public AuthViewController(SignInManager<IdentityUser> signInManager)
public AccountController(SignInManager<IdentityUser> signInManager)
{
_signInManager = signInManager;
}
@@ -26,7 +26,7 @@ public class AuthViewController : Controller
return View();
}
[HttpPost("Logout")]
[HttpGet("Logout")]
public async Task<IActionResult> Logout()
{
await _signInManager.SignOutAsync();

View File

@@ -23,7 +23,7 @@ public class HomeController : Controller
{
return RedirectToAction("Dashboard");
}
return RedirectToAction("Login", "AuthViewController");
return RedirectToAction("Login", "AccountController");
}
public async Task<IActionResult> Dashboard()

View File

@@ -0,0 +1,402 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using OneForMe.Data;
#nullable disable
namespace OneForMe.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20251129215458_AddOrderNameField")]
partial class AddOrderNameField
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "10.0.0-rc.2.25502.107");
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.IdentityUser", 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("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("OneForMe.Models.MenuItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("OrderId")
.HasColumnType("INTEGER");
b.Property<decimal>("Price")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("OrderId");
b.ToTable("MenuItems");
});
modelBuilder.Entity("OneForMe.Models.Order", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime?>("ClosedAt")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<string>("CreatorName")
.IsRequired()
.HasColumnType("TEXT");
b.Property<bool>("IsClosed")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("OrderCode")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("OrderCode")
.IsUnique();
b.ToTable("Orders");
});
modelBuilder.Entity("OneForMe.Models.OrderItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("MenuItemId")
.HasColumnType("INTEGER");
b.Property<int>("OrderId")
.HasColumnType("INTEGER");
b.Property<DateTime>("OrderedAt")
.HasColumnType("TEXT");
b.Property<string>("ParticipantEmail")
.HasColumnType("TEXT");
b.Property<string>("ParticipantName")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("Quantity")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("MenuItemId");
b.HasIndex("OrderId");
b.ToTable("OrderItems");
});
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("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", 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("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("OneForMe.Models.MenuItem", b =>
{
b.HasOne("OneForMe.Models.Order", "Order")
.WithMany("MenuItems")
.HasForeignKey("OrderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Order");
});
modelBuilder.Entity("OneForMe.Models.OrderItem", b =>
{
b.HasOne("OneForMe.Models.MenuItem", "MenuItem")
.WithMany("OrderItems")
.HasForeignKey("MenuItemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("OneForMe.Models.Order", "Order")
.WithMany("OrderItems")
.HasForeignKey("OrderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("MenuItem");
b.Navigation("Order");
});
modelBuilder.Entity("OneForMe.Models.MenuItem", b =>
{
b.Navigation("OrderItems");
});
modelBuilder.Entity("OneForMe.Models.Order", b =>
{
b.Navigation("MenuItems");
b.Navigation("OrderItems");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace OneForMe.Migrations
{
/// <inheritdoc />
public partial class AddOrderNameField : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Name",
table: "Orders",
type: "TEXT",
nullable: false,
defaultValue: "");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Name",
table: "Orders");
}
}
}

View File

@@ -251,6 +251,10 @@ namespace OneForMe.Migrations
b.Property<bool>("IsClosed")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("OrderCode")
.IsRequired()
.HasColumnType("TEXT");

View File

@@ -5,6 +5,7 @@ public class Order
public int Id { get; set; }
public string OrderCode { get; set; } = string.Empty;
public string CreatorName { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime? ClosedAt { get; set; }
public bool IsClosed { get; set; } = false;

View File

@@ -231,4 +231,40 @@
<data name="AddItemsThatPeopleCanOrder" xml:space="preserve">
<value>Fügen Sie Artikel hinzu, die Menschen bestellen können</value>
</data>
<data name="Login" xml:space="preserve">
<value>Anmelden</value>
</data>
<data name="Email" xml:space="preserve">
<value>E-Mail</value>
</data>
<data name="Password" xml:space="preserve">
<value>Passwort</value>
</data>
<data name="DontHaveAccount" xml:space="preserve">
<value>Haben Sie kein Konto?</value>
</data>
<data name="RegisterHere" xml:space="preserve">
<value>Hier registrieren</value>
</data>
<data name="AnErrorOccurred" xml:space="preserve">
<value>Ein Fehler ist aufgetreten:</value>
</data>
<data name="Register" xml:space="preserve">
<value>Registrieren</value>
</data>
<data name="ConfirmPassword" xml:space="preserve">
<value>Passwort bestätigen</value>
</data>
<data name="AlreadyHaveAccount" xml:space="preserve">
<value>Haben Sie bereits ein Konto?</value>
</data>
<data name="LoginHere" xml:space="preserve">
<value>Hier anmelden</value>
</data>
<data name="PasswordsDoNotMatch" xml:space="preserve">
<value>Passwörter stimmen nicht überein!</value>
</data>
<data name="RegistrationSuccessful" xml:space="preserve">
<value>Registrierung erfolgreich! Leitung zum Login...</value>
</data>
</root>

View File

@@ -231,4 +231,40 @@
<data name="AddItemsThatPeopleCanOrder" xml:space="preserve">
<value>Add items that people can order</value>
</data>
<data name="Login" xml:space="preserve">
<value>Login</value>
</data>
<data name="Email" xml:space="preserve">
<value>Email</value>
</data>
<data name="Password" xml:space="preserve">
<value>Password</value>
</data>
<data name="DontHaveAccount" xml:space="preserve">
<value>Don't have an account?</value>
</data>
<data name="RegisterHere" xml:space="preserve">
<value>Register here</value>
</data>
<data name="AnErrorOccurred" xml:space="preserve">
<value>An error occurred:</value>
</data>
<data name="Register" xml:space="preserve">
<value>Register</value>
</data>
<data name="ConfirmPassword" xml:space="preserve">
<value>Confirm Password</value>
</data>
<data name="AlreadyHaveAccount" xml:space="preserve">
<value>Already have an account?</value>
</data>
<data name="LoginHere" xml:space="preserve">
<value>Login here</value>
</data>
<data name="PasswordsDoNotMatch" xml:space="preserve">
<value>Passwords do not match!</value>
</data>
<data name="RegistrationSuccessful" xml:space="preserve">
<value>Registration successful! Redirecting to login...</value>
</data>
</root>

View File

@@ -1,5 +1,8 @@
@using OneForMe.Services
@inject LocalizationService Localizer
@{
ViewData["Title"] = "Login";
ViewData["Title"] = Localizer["Login"];
}
<div class="container mt-5">
@@ -7,25 +10,25 @@
<div class="col-md-6">
<div class="card shadow">
<div class="card-body p-5">
<h2 class="text-center mb-4">Login</h2>
<h2 class="text-center mb-4">@Localizer["Login"]</h2>
<form id="loginForm">
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<label for="email" class="form-label">@Localizer["Email"]</label>
<input type="email" class="form-control" id="email" name="email" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<label for="password" class="form-label">@Localizer["Password"]</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary w-100">Login</button>
<button type="submit" class="btn btn-primary w-100">@Localizer["Login"]</button>
</form>
<hr>
<p class="text-center">Don't have an account? <a asp-controller="AuthView" asp-action="Register">Register here</a></p>
<p class="text-center">@Localizer["DontHaveAccount"] <a asp-controller="Account" asp-action="Register">@Localizer["RegisterHere"]</a></p>
<div id="message" class="mt-3"></div>
</div>
@@ -52,16 +55,13 @@ document.getElementById('loginForm').addEventListener('submit', async (e) => {
});
if (response.ok) {
messageDiv.innerHTML = '<div class="alert alert-success">Login successful! Redirecting...</div>';
setTimeout(() => {
window.location.href = '/';
}, 1500);
window.location.href = '/';
} else {
const error = await response.json();
messageDiv.innerHTML = `<div class="alert alert-danger">${error.message}</div>`;
}
} catch (error) {
messageDiv.innerHTML = `<div class="alert alert-danger">An error occurred: ${error.message}</div>`;
messageDiv.innerHTML = `<div class="alert alert-danger">@Localizer["AnErrorOccurred"] ${error.message}</div>`;
}
});
</script>

View File

@@ -1,5 +1,8 @@
@using OneForMe.Services
@inject LocalizationService Localizer
@{
ViewData["Title"] = "Register";
ViewData["Title"] = Localizer["Register"];
}
<div class="container mt-5">
@@ -7,30 +10,30 @@
<div class="col-md-6">
<div class="card shadow">
<div class="card-body p-5">
<h2 class="text-center mb-4">Register</h2>
<h2 class="text-center mb-4">@Localizer["Register"]</h2>
<form id="registerForm">
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<label for="email" class="form-label">@Localizer["Email"]</label>
<input type="email" class="form-control" id="email" name="email" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<label for="password" class="form-label">@Localizer["Password"]</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<div class="mb-3">
<label for="confirmPassword" class="form-label">Confirm Password</label>
<label for="confirmPassword" class="form-label">@Localizer["ConfirmPassword"]</label>
<input type="password" class="form-control" id="confirmPassword" name="confirmPassword" required>
</div>
<button type="submit" class="btn btn-primary w-100">Register</button>
<button type="submit" class="btn btn-primary w-100">@Localizer["Register"]</button>
</form>
<hr>
<p class="text-center">Already have an account? <a href="/auth/login">Login here</a></p>
<p class="text-center">@Localizer["AlreadyHaveAccount"] <a asp-controller="Account" asp-action="Login">@Localizer["LoginHere"]</a></p>
<div id="message" class="mt-3"></div>
</div>
@@ -49,7 +52,7 @@ document.getElementById('registerForm').addEventListener('submit', async (e) =>
const messageDiv = document.getElementById('message');
if (password !== confirmPassword) {
messageDiv.innerHTML = '<div class="alert alert-danger">Passwords do not match!</div>';
messageDiv.innerHTML = '<div class="alert alert-danger">@Localizer["PasswordsDoNotMatch"]</div>';
return;
}
@@ -63,9 +66,9 @@ document.getElementById('registerForm').addEventListener('submit', async (e) =>
});
if (response.ok) {
messageDiv.innerHTML = '<div class="alert alert-success">Registration successful! Redirecting to login...</div>';
messageDiv.innerHTML = '<div class="alert alert-success">@Localizer["RegistrationSuccessful"]</div>';
setTimeout(() => {
window.location.href = '/AuthView/Login';
window.location.href = '/Account/Login';
}, 1500);
} else {
const error = await response.json();
@@ -73,7 +76,7 @@ document.getElementById('registerForm').addEventListener('submit', async (e) =>
messageDiv.innerHTML = `<div class="alert alert-danger">${errorMessages}</div>`;
}
} catch (error) {
messageDiv.innerHTML = `<div class="alert alert-danger">An error occurred: ${error.message}</div>`;
messageDiv.innerHTML = `<div class="alert alert-danger">@Localizer["AnErrorOccurred"] ${error.message}</div>`;
}
});
</script>

View File

@@ -12,7 +12,7 @@
<div class="col-md-12">
<h1>@Localizer.Get("Welcome")</h1>
<p>@Localizer.Get("LoggedInAs"): <strong>@User.Identity?.Name</strong></p>
<a href="/AuthViewController/Logout" class="btn btn-danger">@Localizer.Get("Logout")</a>
<a href="/Account/Logout" class="btn btn-danger">@Localizer.Get("Logout")</a>
</div>
</div>
@@ -57,7 +57,7 @@
<div class="col-md-6 mb-3">
<div class="card shadow">
<div class="card-body">
<h5 class="card-title">@order.CreatorName</h5>
<h5 class="card-title">@order.Name</h5>
<p class="card-text">
<small class="text-muted">@Localizer.Get("Code"): <strong>@order.OrderCode</strong></small><br>
<small class="text-muted">@Localizer.Get("Created"): @order.CreatedAt.ToString("MMM dd, yyyy HH:mm")</small><br>

View File

@@ -14,8 +14,8 @@
<form method="post" id="createOrderForm">
<div class="mb-3">
<label for="creatorName" class="form-label">@Localizer["OrderName"]</label>
<input type="text" class="form-control" id="creatorName" name="creatorName" placeholder="e.g., Pizza Party" required>
<label for="Name" class="form-label">@Localizer["OrderName"]</label>
<input type="text" class="form-control" id="Name" name="Name" placeholder="e.g., Pizza Party" required>
<small class="text-muted">@Localizer["GiveOrderName"]</small>
</div>

View File

@@ -12,7 +12,7 @@
<div class="col-md-8">
<div class="card shadow mb-4">
<div class="card-body">
<h2>@Model.CreatorName</h2>
<h2>@Model.Name</h2>
<p class="text-muted">@Localizer.Get("Code"): <strong>@Model.OrderCode</strong></p>
<p>@Localizer.Get("CreatedBy"): <strong>@Model.CreatorName</strong></p>
<p>@Localizer.Get("Status"): <span class="badge @(Model.IsClosed ? "bg-danger" : "bg-success")">@(Model.IsClosed ? Localizer.Get("Closed") : Localizer.Get("Open"))</span></p>

View File

@@ -23,10 +23,15 @@
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
</ul>
@if (User.Identity?.IsAuthenticated ?? false)
{
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
<a class="nav-link text-dark" asp-area="" asp-controller="Account" asp-action="Logout">Logout</a>
</li>
</ul>
}
</div>
</div>
</nav>