Fix admin route access and backend configuration

- Added /admin redirect to login page in nginx config
- Fixed backend server.js route ordering for proper admin handling
- Updated authentication middleware and routes
- Added user management routes
- Configured PostgreSQL integration
- Updated environment configuration
This commit is contained in:
Local Server
2025-12-13 22:34:11 -06:00
parent 8bb6430a70
commit 703ab57984
253 changed files with 29870 additions and 157 deletions

View File

@@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace SkyArtShop.Data;
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base((DbContextOptions)options)
{
}
}

8
Data/ApplicationUser.cs Normal file
View File

@@ -0,0 +1,8 @@
using Microsoft.AspNetCore.Identity;
namespace SkyArtShop.Data;
public class ApplicationUser : IdentityUser
{
public string DisplayName { get; set; } = string.Empty;
}

172
Data/SkyArtShopDbContext.cs Normal file
View File

@@ -0,0 +1,172 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using SkyArtShop.Models;
namespace SkyArtShop.Data;
public class SkyArtShopDbContext : DbContext
{
public DbSet<Page> Pages { get; set; }
public DbSet<PortfolioCategory> PortfolioCategories { get; set; }
public DbSet<PortfolioProject> PortfolioProjects { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<BlogPost> BlogPosts { get; set; }
public DbSet<SiteSettings> SiteSettings { get; set; }
public DbSet<MenuItem> MenuItems { get; set; }
public DbSet<AdminUser> AdminUsers { get; set; }
public DbSet<UserRole> UserRoles { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<ProductView> ProductViews { get; set; }
public DbSet<HomepageSection> HomepageSections { get; set; }
public SkyArtShopDbContext(DbContextOptions<SkyArtShopDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity(delegate(EntityTypeBuilder<Page> entity)
{
entity.HasKey((Page e) => e.Id);
entity.Property((Page e) => e.Id).ValueGeneratedOnAdd();
entity.Property((Page e) => e.PageName).IsRequired().HasMaxLength(200);
entity.Property((Page e) => e.PageSlug).IsRequired().HasMaxLength(200);
entity.HasIndex((Page e) => e.PageSlug).IsUnique();
entity.Property((Page e) => e.Content).HasColumnType("text");
entity.Property((Page e) => e.ImageGallery).HasColumnType("jsonb");
entity.OwnsMany((Page e) => e.TeamMembers, delegate(OwnedNavigationBuilder<Page, TeamMember> tm)
{
tm.Property((TeamMember t) => t.Name).HasMaxLength(200);
tm.Property((TeamMember t) => t.Role).HasMaxLength(200);
tm.Property((TeamMember t) => t.Bio).HasColumnType("text");
});
});
modelBuilder.Entity(delegate(EntityTypeBuilder<PortfolioCategory> entity)
{
entity.HasKey((PortfolioCategory e) => e.Id);
entity.Property((PortfolioCategory e) => e.Id).ValueGeneratedOnAdd();
entity.Property((PortfolioCategory e) => e.Name).IsRequired().HasMaxLength(200);
entity.Property((PortfolioCategory e) => e.Slug).IsRequired().HasMaxLength(200);
entity.HasIndex((PortfolioCategory e) => e.Slug).IsUnique();
});
modelBuilder.Entity(delegate(EntityTypeBuilder<PortfolioProject> entity)
{
entity.HasKey((PortfolioProject e) => e.Id);
entity.Property((PortfolioProject e) => e.Id).ValueGeneratedOnAdd();
entity.Property((PortfolioProject e) => e.Title).IsRequired().HasMaxLength(300);
entity.Property((PortfolioProject e) => e.CategoryId).IsRequired().HasMaxLength(50);
entity.Property((PortfolioProject e) => e.Description).HasColumnType("text");
entity.Property((PortfolioProject e) => e.Images).HasColumnType("jsonb");
});
modelBuilder.Entity(delegate(EntityTypeBuilder<Product> entity)
{
entity.HasKey((Product e) => e.Id);
entity.Property((Product e) => e.Id).ValueGeneratedOnAdd();
entity.Property((Product e) => e.Name).IsRequired().HasMaxLength(300);
entity.Property((Product e) => e.Slug).IsRequired().HasMaxLength(300);
entity.HasIndex((Product e) => e.Slug).IsUnique();
entity.Property((Product e) => e.SKU).HasMaxLength(100);
entity.Property((Product e) => e.Description).HasColumnType("text");
entity.Property((Product e) => e.Price).HasColumnType("numeric(18,2)");
entity.Property((Product e) => e.Colors).HasColumnType("jsonb");
entity.Property((Product e) => e.Images).HasColumnType("jsonb");
entity.Property((Product e) => e.Tags).HasColumnType("jsonb");
entity.Property((Product e) => e.TotalRevenue).HasColumnType("numeric(18,2)");
entity.Property((Product e) => e.CostPrice).HasColumnType("numeric(18,2)");
entity.OwnsMany((Product e) => e.Variants, delegate(OwnedNavigationBuilder<Product, ProductVariant> v)
{
v.Property((ProductVariant pv) => pv.ColorName).HasMaxLength(100);
v.Property((ProductVariant pv) => pv.ColorHex).HasMaxLength(20);
v.Property((ProductVariant pv) => pv.Images).HasColumnType("jsonb");
v.Property((ProductVariant pv) => pv.SKU).HasMaxLength(100);
v.Property((ProductVariant pv) => pv.PriceAdjustment).HasColumnType("numeric(18,2)");
});
});
modelBuilder.Entity(delegate(EntityTypeBuilder<BlogPost> entity)
{
entity.HasKey((BlogPost e) => e.Id);
entity.Property((BlogPost e) => e.Id).ValueGeneratedOnAdd();
entity.Property((BlogPost e) => e.Title).IsRequired().HasMaxLength(300);
entity.Property((BlogPost e) => e.Slug).IsRequired().HasMaxLength(300);
entity.HasIndex((BlogPost e) => e.Slug).IsUnique();
entity.Property((BlogPost e) => e.Content).HasColumnType("text");
entity.Property((BlogPost e) => e.Tags).HasColumnType("jsonb");
});
modelBuilder.Entity(delegate(EntityTypeBuilder<SiteSettings> entity)
{
entity.HasKey((SiteSettings e) => e.Id);
entity.Property((SiteSettings e) => e.Id).ValueGeneratedOnAdd();
});
modelBuilder.Entity(delegate(EntityTypeBuilder<MenuItem> entity)
{
entity.HasKey((MenuItem e) => e.Id);
entity.Property((MenuItem e) => e.Id).ValueGeneratedOnAdd();
entity.Property((MenuItem e) => e.Label).IsRequired().HasMaxLength(200);
entity.Property((MenuItem e) => e.Url).IsRequired().HasMaxLength(500);
});
modelBuilder.Entity(delegate(EntityTypeBuilder<AdminUser> entity)
{
entity.HasKey((AdminUser e) => e.Id);
entity.Property((AdminUser e) => e.Id).ValueGeneratedOnAdd();
entity.Property((AdminUser e) => e.Email).IsRequired().HasMaxLength(256);
entity.HasIndex((AdminUser e) => e.Email).IsUnique();
entity.Property((AdminUser e) => e.PasswordHash).IsRequired().HasMaxLength(500);
entity.Property((AdminUser e) => e.Name).IsRequired().HasMaxLength(200);
entity.Property((AdminUser e) => e.Role).IsRequired().HasMaxLength(100);
entity.Property((AdminUser e) => e.Permissions).HasColumnType("jsonb");
});
modelBuilder.Entity(delegate(EntityTypeBuilder<UserRole> entity)
{
entity.HasKey((UserRole e) => e.Id);
entity.Property((UserRole e) => e.Id).ValueGeneratedOnAdd();
entity.Property((UserRole e) => e.RoleName).IsRequired().HasMaxLength(100);
entity.HasIndex((UserRole e) => e.RoleName).IsUnique();
entity.Property((UserRole e) => e.Permissions).HasColumnType("jsonb");
});
modelBuilder.Entity(delegate(EntityTypeBuilder<Order> entity)
{
entity.HasKey((Order e) => e.Id);
entity.Property((Order e) => e.Id).ValueGeneratedOnAdd();
entity.Property((Order e) => e.CustomerEmail).HasMaxLength(256);
entity.Property((Order e) => e.CustomerName).HasMaxLength(200);
entity.Property((Order e) => e.TotalAmount).HasColumnType("numeric(18,2)");
entity.OwnsMany((Order e) => e.Items, delegate(OwnedNavigationBuilder<Order, OrderItem> oi)
{
oi.Property((OrderItem o) => o.ProductId).HasMaxLength(50);
oi.Property((OrderItem o) => o.ProductName).HasMaxLength(300);
oi.Property((OrderItem o) => o.SKU).HasMaxLength(100);
oi.Property((OrderItem o) => o.Price).HasColumnType("numeric(18,2)");
oi.Property((OrderItem o) => o.Subtotal).HasColumnType("numeric(18,2)");
});
});
modelBuilder.Entity(delegate(EntityTypeBuilder<ProductView> entity)
{
entity.HasKey((ProductView e) => e.Id);
entity.Property((ProductView e) => e.Id).ValueGeneratedOnAdd();
entity.Property((ProductView e) => e.ProductId).HasMaxLength(50);
entity.Property((ProductView e) => e.SessionId).HasMaxLength(200);
entity.Property((ProductView e) => e.IpAddress).HasMaxLength(50);
});
modelBuilder.Entity(delegate(EntityTypeBuilder<HomepageSection> entity)
{
entity.HasKey((HomepageSection e) => e.Id);
entity.Property((HomepageSection e) => e.Id).ValueGeneratedOnAdd();
entity.Property((HomepageSection e) => e.SectionType).HasMaxLength(100);
entity.Property((HomepageSection e) => e.Content).HasColumnType("text");
entity.Property((HomepageSection e) => e.AdditionalData).HasColumnType("jsonb");
});
}
}