Jostka
This commit is contained in:
@@ -7,6 +7,7 @@ public interface IUnitOfWork
|
|||||||
public IProductRepository ProductRepository { get; }
|
public IProductRepository ProductRepository { get; }
|
||||||
public ICategoryRepository CategoryRepository { get; }
|
public ICategoryRepository CategoryRepository { get; }
|
||||||
public IProductVariantRepository ProductVariantRepository { get; }
|
public IProductVariantRepository ProductVariantRepository { get; }
|
||||||
|
public IUserRepository UserRepository { get; }
|
||||||
|
|
||||||
Task SaveAsync(CancellationToken cancellationToken = default);
|
Task SaveAsync(CancellationToken cancellationToken = default);
|
||||||
Task BeginTransactionAsync(CancellationToken cancellationToken = default);
|
Task BeginTransactionAsync(CancellationToken cancellationToken = default);
|
||||||
|
|||||||
31
src/Imprink.Application/Users/SyncUserHandler.cs
Normal file
31
src/Imprink.Application/Users/SyncUserHandler.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using Imprink.Domain.Common.Models;
|
||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace Imprink.Application.Users;
|
||||||
|
|
||||||
|
public record SyncUserCommand(Auth0User User) : IRequest<bool>;
|
||||||
|
|
||||||
|
public class SyncUserHandler(IUnitOfWork uw): IRequestHandler<SyncUserCommand, bool>
|
||||||
|
{
|
||||||
|
public async Task<bool> Handle(SyncUserCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await uw.BeginTransactionAsync(cancellationToken);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!await uw.UserRepository.UpdateOrCreateUserAsync(request.User, cancellationToken))
|
||||||
|
{
|
||||||
|
await uw.RollbackTransactionAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
await uw.SaveAsync(cancellationToken);
|
||||||
|
await uw.CommitTransactionAsync(cancellationToken);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
await uw.RollbackTransactionAsync(cancellationToken);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
|
|
||||||
namespace Imprink.Domain.Common.Models;
|
namespace Imprink.Domain.Common.Models;
|
||||||
|
|
||||||
public class Auth0User
|
public class Auth0User
|
||||||
|
|||||||
@@ -5,19 +5,19 @@ namespace Imprink.Domain.Entities.Users;
|
|||||||
public class User
|
public class User
|
||||||
{
|
{
|
||||||
public string Id { get; set; } = null!;
|
public string Id { get; set; } = null!;
|
||||||
|
public required string Name { get; set; }
|
||||||
|
public required string Nickname { get; set; }
|
||||||
public required string Email { get; set; }
|
public required string Email { get; set; }
|
||||||
public required string FirstName { get; set; }
|
|
||||||
public required string LastName { get; set; }
|
public bool EmailVerified { get; set; }
|
||||||
|
public string? FullName { get; set; }
|
||||||
public string? PhoneNumber { get; set; }
|
public string? PhoneNumber { get; set; }
|
||||||
public DateTime? DateOfBirth { get; set; }
|
|
||||||
public required bool IsActive { get; set; }
|
public required bool IsActive { get; set; }
|
||||||
public DateTime? LastLoginAt { get; set; }
|
|
||||||
|
|
||||||
public virtual ICollection<Address> Addresses { get; set; } = new List<Address>();
|
public virtual ICollection<Address> Addresses { get; set; } = new List<Address>();
|
||||||
public virtual ICollection<UserRole> UserRoles { get; set; } = new List<UserRole>();
|
public virtual ICollection<UserRole> UserRoles { get; set; } = new List<UserRole>();
|
||||||
public virtual ICollection<Order> Orders { get; set; } = new List<Order>();
|
public virtual ICollection<Order> Orders { get; set; } = new List<Order>();
|
||||||
|
|
||||||
public string FullName => $"{FirstName} {LastName}";
|
public Address? DefaultAddress => Addresses.FirstOrDefault(a => a is { IsDefault: true, IsActive: true });
|
||||||
public Address? DefaultAddress => Addresses.FirstOrDefault(a => a.IsDefault && a.IsActive);
|
|
||||||
public IEnumerable<Role> Roles => UserRoles.Select(ur => ur.Role);
|
public IEnumerable<Role> Roles => UserRoles.Select(ur => ur.Role);
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
|
using Imprink.Domain.Common.Models;
|
||||||
using Imprink.Domain.Entities.Users;
|
using Imprink.Domain.Entities.Users;
|
||||||
|
|
||||||
namespace Imprink.Domain.Repositories;
|
namespace Imprink.Domain.Repositories;
|
||||||
|
|
||||||
public interface IUserRepository
|
public interface IUserRepository
|
||||||
{
|
{
|
||||||
|
Task<bool> UpdateOrCreateUserAsync(Auth0User user, CancellationToken cancellationToken = default);
|
||||||
Task<User?> GetUserByIdAsync(string userId, CancellationToken cancellationToken = default);
|
Task<User?> GetUserByIdAsync(string userId, CancellationToken cancellationToken = default);
|
||||||
Task<User?> GetUserByEmailAsync(string email, CancellationToken cancellationToken = default);
|
Task<User?> GetUserByEmailAsync(string email, CancellationToken cancellationToken = default);
|
||||||
Task<IEnumerable<User>> GetAllUsersAsync(CancellationToken cancellationToken = default);
|
Task<IEnumerable<User>> GetAllUsersAsync(CancellationToken cancellationToken = default);
|
||||||
@@ -18,19 +20,8 @@ public interface IUserRepository
|
|||||||
|
|
||||||
Task<bool> ActivateUserAsync(string userId, CancellationToken cancellationToken = default);
|
Task<bool> ActivateUserAsync(string userId, CancellationToken cancellationToken = default);
|
||||||
Task<bool> DeactivateUserAsync(string userId, CancellationToken cancellationToken = default);
|
Task<bool> DeactivateUserAsync(string userId, CancellationToken cancellationToken = default);
|
||||||
Task UpdateLastLoginAsync(string userId, DateTime loginTime, CancellationToken cancellationToken = default);
|
|
||||||
|
|
||||||
Task<IEnumerable<User>> SearchUsersAsync(string searchTerm, CancellationToken cancellationToken = default);
|
|
||||||
Task<IEnumerable<User>> GetUsersByRoleAsync(Guid roleId, CancellationToken cancellationToken = default);
|
Task<IEnumerable<User>> GetUsersByRoleAsync(Guid roleId, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
Task<(IEnumerable<User> Users, int TotalCount)> GetUsersPagedAsync(
|
|
||||||
int pageNumber,
|
|
||||||
int pageSize,
|
|
||||||
string? searchTerm = null,
|
|
||||||
bool? isActive = null,
|
|
||||||
CancellationToken cancellationToken = default);
|
|
||||||
|
|
||||||
Task<User?> GetUserWithAddressesAsync(string userId, CancellationToken cancellationToken = default);
|
|
||||||
Task<User?> GetUserWithRolesAsync(string userId, CancellationToken cancellationToken = default);
|
|
||||||
Task<User?> GetUserWithAllRelatedDataAsync(string userId, CancellationToken cancellationToken = default);
|
Task<User?> GetUserWithAllRelatedDataAsync(string userId, CancellationToken cancellationToken = default);
|
||||||
}
|
}
|
||||||
@@ -15,28 +15,29 @@ public class UserConfiguration : IEntityTypeConfiguration<User>
|
|||||||
builder.Property(u => u.Email)
|
builder.Property(u => u.Email)
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasMaxLength(256);
|
.HasMaxLength(256);
|
||||||
|
|
||||||
builder.Property(u => u.FirstName)
|
builder.Property(u => u.Name)
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasMaxLength(100);
|
.HasMaxLength(100);
|
||||||
|
|
||||||
builder.Property(u => u.LastName)
|
builder.Property(u => u.Nickname)
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasMaxLength(100);
|
.HasMaxLength(100);
|
||||||
|
|
||||||
|
builder.Property(u => u.EmailVerified)
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(100);
|
||||||
|
|
||||||
|
builder.Property(u => u.FullName)
|
||||||
|
.HasMaxLength(100);
|
||||||
|
|
||||||
builder.Property(u => u.PhoneNumber)
|
builder.Property(u => u.PhoneNumber)
|
||||||
.HasMaxLength(20);
|
.HasMaxLength(20);
|
||||||
|
|
||||||
builder.Property(u => u.DateOfBirth)
|
|
||||||
.HasColumnType("date");
|
|
||||||
|
|
||||||
builder.Property(u => u.IsActive)
|
builder.Property(u => u.IsActive)
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasDefaultValue(true);
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
builder.Property(u => u.LastLoginAt)
|
|
||||||
.HasColumnType("datetime2");
|
|
||||||
|
|
||||||
builder.HasIndex(u => u.Email)
|
builder.HasIndex(u => u.Email)
|
||||||
.IsUnique()
|
.IsUnique()
|
||||||
.HasDatabaseName("IX_User_Email");
|
.HasDatabaseName("IX_User_Email");
|
||||||
@@ -50,7 +51,6 @@ public class UserConfiguration : IEntityTypeConfiguration<User>
|
|||||||
.HasPrincipalKey(u => u.Id)
|
.HasPrincipalKey(u => u.Id)
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
builder.Ignore(u => u.FullName);
|
|
||||||
builder.Ignore(u => u.DefaultAddress);
|
builder.Ignore(u => u.DefaultAddress);
|
||||||
builder.Ignore(u => u.Roles);
|
builder.Ignore(u => u.Roles);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|||||||
namespace Imprink.Infrastructure.Migrations
|
namespace Imprink.Infrastructure.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(ApplicationDbContext))]
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
[Migration("20250607211109_InitialSetup")]
|
[Migration("20250608204903_InitialSetup")]
|
||||||
partial class InitialSetup
|
partial class InitialSetup
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -766,16 +766,16 @@ namespace Imprink.Infrastructure.Migrations
|
|||||||
.HasMaxLength(450)
|
.HasMaxLength(450)
|
||||||
.HasColumnType("nvarchar(450)");
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
b.Property<DateTime?>("DateOfBirth")
|
|
||||||
.HasColumnType("date");
|
|
||||||
|
|
||||||
b.Property<string>("Email")
|
b.Property<string>("Email")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasMaxLength(256)
|
.HasMaxLength(256)
|
||||||
.HasColumnType("nvarchar(256)");
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
b.Property<string>("FirstName")
|
b.Property<bool>("EmailVerified")
|
||||||
.IsRequired()
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("bit");
|
||||||
|
|
||||||
|
b.Property<string>("FullName")
|
||||||
.HasMaxLength(100)
|
.HasMaxLength(100)
|
||||||
.HasColumnType("nvarchar(100)");
|
.HasColumnType("nvarchar(100)");
|
||||||
|
|
||||||
@@ -784,10 +784,12 @@ namespace Imprink.Infrastructure.Migrations
|
|||||||
.HasColumnType("bit")
|
.HasColumnType("bit")
|
||||||
.HasDefaultValue(true);
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
b.Property<DateTime?>("LastLoginAt")
|
b.Property<string>("Name")
|
||||||
.HasColumnType("datetime2");
|
.IsRequired()
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("nvarchar(100)");
|
||||||
|
|
||||||
b.Property<string>("LastName")
|
b.Property<string>("Nickname")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasMaxLength(100)
|
.HasMaxLength(100)
|
||||||
.HasColumnType("nvarchar(100)");
|
.HasColumnType("nvarchar(100)");
|
||||||
@@ -81,13 +81,13 @@ namespace Imprink.Infrastructure.Migrations
|
|||||||
columns: table => new
|
columns: table => new
|
||||||
{
|
{
|
||||||
Id = table.Column<string>(type: "nvarchar(450)", maxLength: 450, nullable: false),
|
Id = table.Column<string>(type: "nvarchar(450)", maxLength: 450, nullable: false),
|
||||||
|
Name = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||||
|
Nickname = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||||
Email = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
|
Email = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
|
||||||
FirstName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
EmailVerified = table.Column<bool>(type: "bit", maxLength: 100, nullable: false),
|
||||||
LastName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
FullName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true),
|
||||||
PhoneNumber = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true),
|
PhoneNumber = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true),
|
||||||
DateOfBirth = table.Column<DateTime>(type: "date", nullable: true),
|
IsActive = table.Column<bool>(type: "bit", nullable: false, defaultValue: true)
|
||||||
IsActive = table.Column<bool>(type: "bit", nullable: false, defaultValue: true),
|
|
||||||
LastLoginAt = table.Column<DateTime>(type: "datetime2", nullable: true)
|
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
||||||
@@ -763,16 +763,16 @@ namespace Imprink.Infrastructure.Migrations
|
|||||||
.HasMaxLength(450)
|
.HasMaxLength(450)
|
||||||
.HasColumnType("nvarchar(450)");
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
b.Property<DateTime?>("DateOfBirth")
|
|
||||||
.HasColumnType("date");
|
|
||||||
|
|
||||||
b.Property<string>("Email")
|
b.Property<string>("Email")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasMaxLength(256)
|
.HasMaxLength(256)
|
||||||
.HasColumnType("nvarchar(256)");
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
b.Property<string>("FirstName")
|
b.Property<bool>("EmailVerified")
|
||||||
.IsRequired()
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("bit");
|
||||||
|
|
||||||
|
b.Property<string>("FullName")
|
||||||
.HasMaxLength(100)
|
.HasMaxLength(100)
|
||||||
.HasColumnType("nvarchar(100)");
|
.HasColumnType("nvarchar(100)");
|
||||||
|
|
||||||
@@ -781,10 +781,12 @@ namespace Imprink.Infrastructure.Migrations
|
|||||||
.HasColumnType("bit")
|
.HasColumnType("bit")
|
||||||
.HasDefaultValue(true);
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
b.Property<DateTime?>("LastLoginAt")
|
b.Property<string>("Name")
|
||||||
.HasColumnType("datetime2");
|
.IsRequired()
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("nvarchar(100)");
|
||||||
|
|
||||||
b.Property<string>("LastName")
|
b.Property<string>("Nickname")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasMaxLength(100)
|
.HasMaxLength(100)
|
||||||
.HasColumnType("nvarchar(100)");
|
.HasColumnType("nvarchar(100)");
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Imprink.Domain.Common.Models;
|
||||||
using Imprink.Domain.Entities.Users;
|
using Imprink.Domain.Entities.Users;
|
||||||
using Imprink.Domain.Repositories;
|
using Imprink.Domain.Repositories;
|
||||||
using Imprink.Infrastructure.Database;
|
using Imprink.Infrastructure.Database;
|
||||||
@@ -7,6 +8,37 @@ namespace Imprink.Infrastructure.Repositories;
|
|||||||
|
|
||||||
public class UserRepository(ApplicationDbContext context) : IUserRepository
|
public class UserRepository(ApplicationDbContext context) : IUserRepository
|
||||||
{
|
{
|
||||||
|
public async Task<bool> UpdateOrCreateUserAsync(Auth0User user, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var userToUpdate = await context.Users
|
||||||
|
.Where(u => u.Id.Equals(user.Sub))
|
||||||
|
.FirstOrDefaultAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (userToUpdate == null)
|
||||||
|
{
|
||||||
|
var newUser = new User
|
||||||
|
{
|
||||||
|
Id = user.Sub,
|
||||||
|
Email = user.Email,
|
||||||
|
EmailVerified = user.EmailVerified,
|
||||||
|
Name = user.Name,
|
||||||
|
Nickname = user.Nickname,
|
||||||
|
IsActive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
context.Users.Add(newUser);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
userToUpdate.Email = user.Email;
|
||||||
|
userToUpdate.Name = user.Name;
|
||||||
|
userToUpdate.Nickname = user.Nickname;
|
||||||
|
userToUpdate.EmailVerified = user.EmailVerified;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<User?> GetUserByIdAsync(string userId, CancellationToken cancellationToken = default)
|
public async Task<User?> GetUserByIdAsync(string userId, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return await context.Users
|
return await context.Users
|
||||||
@@ -92,26 +124,6 @@ public class UserRepository(ApplicationDbContext context) : IUserRepository
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateLastLoginAsync(string userId, DateTime loginTime, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
var user = await context.Users.FindAsync(new object[] { userId }, cancellationToken);
|
|
||||||
if (user != null)
|
|
||||||
{
|
|
||||||
user.LastLoginAt = loginTime;
|
|
||||||
await context.SaveChangesAsync(cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IEnumerable<User>> SearchUsersAsync(string searchTerm, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
return await context.Users
|
|
||||||
.AsNoTracking()
|
|
||||||
.Where(u => u.Email.Contains(searchTerm) ||
|
|
||||||
u.FirstName.Contains(searchTerm) ||
|
|
||||||
u.LastName.Contains(searchTerm))
|
|
||||||
.ToListAsync(cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IEnumerable<User>> GetUsersByRoleAsync(Guid roleId, CancellationToken cancellationToken = default)
|
public async Task<IEnumerable<User>> GetUsersByRoleAsync(Guid roleId, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return await context.Users
|
return await context.Users
|
||||||
@@ -120,54 +132,6 @@ public class UserRepository(ApplicationDbContext context) : IUserRepository
|
|||||||
.ToListAsync(cancellationToken);
|
.ToListAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<(IEnumerable<User> Users, int TotalCount)> GetUsersPagedAsync(
|
|
||||||
int pageNumber,
|
|
||||||
int pageSize,
|
|
||||||
string? searchTerm = null,
|
|
||||||
bool? isActive = null,
|
|
||||||
CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
var query = context.Users.AsNoTracking();
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(searchTerm))
|
|
||||||
{
|
|
||||||
query = query.Where(u => u.Email.Contains(searchTerm) ||
|
|
||||||
u.FirstName.Contains(searchTerm) ||
|
|
||||||
u.LastName.Contains(searchTerm));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isActive.HasValue)
|
|
||||||
{
|
|
||||||
query = query.Where(u => u.IsActive == isActive.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
var totalCount = await query.CountAsync(cancellationToken);
|
|
||||||
|
|
||||||
var users = await query
|
|
||||||
.Skip((pageNumber - 1) * pageSize)
|
|
||||||
.Take(pageSize)
|
|
||||||
.ToListAsync(cancellationToken);
|
|
||||||
|
|
||||||
return (users, totalCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<User?> GetUserWithAddressesAsync(string userId, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
return await context.Users
|
|
||||||
.AsNoTracking()
|
|
||||||
.Include(u => u.Addresses)
|
|
||||||
.FirstOrDefaultAsync(u => u.Id == userId, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<User?> GetUserWithRolesAsync(string userId, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
return await context.Users
|
|
||||||
.AsNoTracking()
|
|
||||||
.Include(u => u.UserRoles)
|
|
||||||
.ThenInclude(ur => ur.Role)
|
|
||||||
.FirstOrDefaultAsync(u => u.Id == userId, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<User?> GetUserWithAllRelatedDataAsync(string userId, CancellationToken cancellationToken = default)
|
public async Task<User?> GetUserWithAllRelatedDataAsync(string userId, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return await context.Users
|
return await context.Users
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Imprink.Application;
|
using Imprink.Application;
|
||||||
using Imprink.Domain.Repositories;
|
using Imprink.Domain.Repositories;
|
||||||
using Imprink.Infrastructure.Database;
|
using Imprink.Infrastructure.Database;
|
||||||
|
using Microsoft.Identity.Client;
|
||||||
|
|
||||||
namespace Imprink.Infrastructure;
|
namespace Imprink.Infrastructure;
|
||||||
|
|
||||||
@@ -8,11 +9,13 @@ public class UnitOfWork(
|
|||||||
ApplicationDbContext context,
|
ApplicationDbContext context,
|
||||||
IProductRepository productRepository,
|
IProductRepository productRepository,
|
||||||
IProductVariantRepository productVariantRepository,
|
IProductVariantRepository productVariantRepository,
|
||||||
ICategoryRepository categoryRepository) : IUnitOfWork
|
ICategoryRepository categoryRepository,
|
||||||
|
IUserRepository userRepository) : IUnitOfWork
|
||||||
{
|
{
|
||||||
public IProductRepository ProductRepository => productRepository;
|
public IProductRepository ProductRepository => productRepository;
|
||||||
public IProductVariantRepository ProductVariantRepository => productVariantRepository;
|
public IProductVariantRepository ProductVariantRepository => productVariantRepository;
|
||||||
public ICategoryRepository CategoryRepository => categoryRepository;
|
public ICategoryRepository CategoryRepository => categoryRepository;
|
||||||
|
public IUserRepository UserRepository => userRepository;
|
||||||
|
|
||||||
public async Task SaveAsync(CancellationToken cancellationToken = default)
|
public async Task SaveAsync(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,23 +1,33 @@
|
|||||||
|
using System.Security.Claims;
|
||||||
|
using Imprink.Application.Users;
|
||||||
|
using Imprink.Domain.Common.Models;
|
||||||
|
using MediatR;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Imprink.WebApi.Controllers.Users;
|
namespace Imprink.WebApi.Controllers.Users;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("/api/[controller]")]
|
[Route("/users")]
|
||||||
public class UserController : ControllerBase
|
public class UserController(IMediator mediator) : ControllerBase
|
||||||
{
|
{
|
||||||
[Authorize]
|
[Authorize]
|
||||||
[HttpPost]
|
[HttpPost("sync")]
|
||||||
public IActionResult SyncUser()
|
public async Task<IActionResult> Sync()
|
||||||
{
|
{
|
||||||
var claims = User.Claims;
|
var enumerable = User.Claims as Claim[] ?? User.Claims.ToArray();
|
||||||
|
|
||||||
foreach (var claim in claims)
|
var auth0User = new Auth0User
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Claim Type: {claim.Type}, Claim Value: {claim.Value}");
|
Sub = enumerable.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value ?? string.Empty,
|
||||||
}
|
Name = enumerable.FirstOrDefault(c => c.Type == "name")?.Value ?? string.Empty,
|
||||||
|
Nickname = enumerable.FirstOrDefault(c => c.Type == "nickname")?.Value ?? string.Empty,
|
||||||
|
Email = enumerable.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value ?? string.Empty,
|
||||||
|
EmailVerified = bool.TryParse(enumerable.FirstOrDefault(c => c.Type == "email_verified")?.Value, out var emailVerified) && emailVerified
|
||||||
|
};
|
||||||
|
|
||||||
|
await mediator.Send(new SyncUserCommand(auth0User));
|
||||||
|
|
||||||
return Ok("Claims logged to console.");
|
return Ok("User Synced.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,9 +112,6 @@ public static class Startup
|
|||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.UseEndpoints(endpoints =>
|
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
|
||||||
{
|
|
||||||
endpoints.MapControllers();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
280
webui/package-lock.json
generated
280
webui/package-lock.json
generated
@@ -9,6 +9,7 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@auth0/nextjs-auth0": "^4.6.1",
|
"@auth0/nextjs-auth0": "^4.6.1",
|
||||||
|
"axios": "^1.9.0",
|
||||||
"next": "15.3.3",
|
"next": "15.3.3",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0"
|
"react-dom": "^19.0.0"
|
||||||
@@ -978,6 +979,23 @@
|
|||||||
"tailwindcss": "4.1.8"
|
"tailwindcss": "4.1.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/asynckit": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/axios": {
|
||||||
|
"version": "1.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz",
|
||||||
|
"integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.15.6",
|
||||||
|
"form-data": "^4.0.0",
|
||||||
|
"proxy-from-env": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/busboy": {
|
"node_modules/busboy": {
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
|
||||||
@@ -989,6 +1007,19 @@
|
|||||||
"node": ">=10.16.0"
|
"node": ">=10.16.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/call-bind-apply-helpers": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"function-bind": "^1.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001720",
|
"version": "1.0.30001720",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001720.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001720.tgz",
|
||||||
@@ -1070,6 +1101,27 @@
|
|||||||
"simple-swizzle": "^0.2.2"
|
"simple-swizzle": "^0.2.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/combined-stream": {
|
||||||
|
"version": "1.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"delayed-stream": "~1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/delayed-stream": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dequal": {
|
"node_modules/dequal": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||||
@@ -1089,6 +1141,20 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dunder-proto": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind-apply-helpers": "^1.0.1",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"gopd": "^1.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/enhanced-resolve": {
|
"node_modules/enhanced-resolve": {
|
||||||
"version": "5.18.1",
|
"version": "5.18.1",
|
||||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz",
|
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz",
|
||||||
@@ -1103,6 +1169,145 @@
|
|||||||
"node": ">=10.13.0"
|
"node": ">=10.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/es-define-property": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es-errors": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es-object-atoms": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es-set-tostringtag": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"get-intrinsic": "^1.2.6",
|
||||||
|
"has-tostringtag": "^1.0.2",
|
||||||
|
"hasown": "^2.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/follow-redirects": {
|
||||||
|
"version": "1.15.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||||
|
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"debug": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/form-data": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"es-set-tostringtag": "^2.1.0",
|
||||||
|
"hasown": "^2.0.2",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/function-bind": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/get-intrinsic": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind-apply-helpers": "^1.0.2",
|
||||||
|
"es-define-property": "^1.0.1",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"es-object-atoms": "^1.1.1",
|
||||||
|
"function-bind": "^1.1.2",
|
||||||
|
"get-proto": "^1.0.1",
|
||||||
|
"gopd": "^1.2.0",
|
||||||
|
"has-symbols": "^1.1.0",
|
||||||
|
"hasown": "^2.0.2",
|
||||||
|
"math-intrinsics": "^1.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/get-proto": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"dunder-proto": "^1.0.1",
|
||||||
|
"es-object-atoms": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/gopd": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/graceful-fs": {
|
"node_modules/graceful-fs": {
|
||||||
"version": "4.2.11",
|
"version": "4.2.11",
|
||||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||||
@@ -1110,6 +1315,45 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/has-symbols": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/has-tostringtag": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"has-symbols": "^1.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/hasown": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"function-bind": "^1.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-arrayish": {
|
"node_modules/is-arrayish": {
|
||||||
"version": "0.3.2",
|
"version": "0.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
|
||||||
@@ -1385,6 +1629,36 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.5.0"
|
"@jridgewell/sourcemap-codec": "^1.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/math-intrinsics": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime-db": {
|
||||||
|
"version": "1.52.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
|
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime-types": {
|
||||||
|
"version": "2.1.35",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||||
|
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"mime-db": "1.52.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/minipass": {
|
"node_modules/minipass": {
|
||||||
"version": "7.1.2",
|
"version": "7.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||||
@@ -1568,6 +1842,12 @@
|
|||||||
"node": "^10 || ^12 || >=14"
|
"node": "^10 || ^12 || >=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/proxy-from-env": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/react": {
|
"node_modules/react": {
|
||||||
"version": "19.1.0",
|
"version": "19.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@auth0/nextjs-auth0": "^4.6.1",
|
"@auth0/nextjs-auth0": "^4.6.1",
|
||||||
|
"axios": "^1.9.0",
|
||||||
"next": "15.3.3",
|
"next": "15.3.3",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0"
|
"react-dom": "^19.0.0"
|
||||||
|
|||||||
@@ -5,22 +5,20 @@ import {useEffect, useState} from "react";
|
|||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const { user, error, isLoading } = useUser();
|
const { user, error, isLoading } = useUser();
|
||||||
const [accessToken, setAccessToken] = useState(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchAccessToken = async () => {
|
const fetchAccessToken = async () => {
|
||||||
if (user) {
|
if (user) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/auth/access-token');
|
|
||||||
const v = await fetch('/token');
|
const v = await fetch('/token');
|
||||||
if (response.ok) {
|
|
||||||
const tokenData = await response.text();
|
|
||||||
setAccessToken(tokenData);
|
|
||||||
} else {
|
|
||||||
setAccessToken('Token not available');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setAccessToken('Error fetching token');
|
console.error("Error fetching token");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const resp = await fetch('/untoken');
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error in /api/untoken:', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -28,10 +26,6 @@ export default function Home() {
|
|||||||
fetchAccessToken().then(r => console.log(r));
|
fetchAccessToken().then(r => console.log(r));
|
||||||
}, [user]);
|
}, [user]);
|
||||||
|
|
||||||
async function checkValidity() {
|
|
||||||
const check = await fetch('https://impr.ink/api/api/User', {method: 'POST'});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gradient-to-br from-purple-900 via-blue-900 to-indigo-900 flex items-center justify-center">
|
<div className="min-h-screen bg-gradient-to-br from-purple-900 via-blue-900 to-indigo-900 flex items-center justify-center">
|
||||||
@@ -147,15 +141,6 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
className="text-purple-300 text-xs font-semibold uppercase tracking-wider">Access
|
|
||||||
Token</label>
|
|
||||||
<div
|
|
||||||
className="text-white/80 text-xs mt-1 p-2 bg-black/30 rounded-lg border border-white/10 font-mono break-all max-h-24 overflow-auto">
|
|
||||||
{accessToken}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -1,34 +1,30 @@
|
|||||||
import { cookies } from 'next/headers';
|
import {cookies, headers} from 'next/headers';
|
||||||
import { NextResponse } from 'next/server';
|
import { NextResponse } from 'next/server';
|
||||||
import {auth0} from "@/lib/auth0";
|
import {auth0} from "@/lib/auth0";
|
||||||
|
import api from "@/lib/api";
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
try {
|
try {
|
||||||
const session = await auth0.getSession();
|
const token = (await auth0.getSession()).tokenSet.accessToken;
|
||||||
const accessToken = session.tokenSet.accessToken;
|
|
||||||
if (!accessToken) {
|
|
||||||
return NextResponse.json({ error: 'No access token found' }, { status: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = NextResponse.json({ message: 'Access token set in cookie' });
|
if (!token) { return NextResponse.json({ error: 'No access token found' }, { status: 401 }); }
|
||||||
|
|
||||||
const cookieDomain = process.env.COOKIE_DOMAIN || undefined;
|
(await cookies()).set('access_token', token, {
|
||||||
|
|
||||||
const cookieStore = await cookies();
|
|
||||||
cookieStore.set({
|
|
||||||
name: 'access_token',
|
|
||||||
value: accessToken,
|
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
secure: true,
|
secure: true,
|
||||||
sameSite: 'strict',
|
sameSite: 'strict',
|
||||||
path: '/',
|
path: '/',
|
||||||
domain: cookieDomain,
|
domain: process.env.COOKIE_DOMAIN,
|
||||||
maxAge: 3600,
|
maxAge: 3600,
|
||||||
});
|
});
|
||||||
|
|
||||||
return response;
|
await api.post('/users/sync', {}, {
|
||||||
|
headers: { Cookie: `access_token=${token}` }
|
||||||
|
});
|
||||||
|
|
||||||
|
NextResponse.json({ message: 'Access token set in cookie' });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error in /api/set-token:', error);
|
console.error('Error in /api/token:', error);
|
||||||
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
|
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
22
webui/src/app/untoken/route.js
Normal file
22
webui/src/app/untoken/route.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import {cookies} from 'next/headers';
|
||||||
|
import {NextResponse} from 'next/server';
|
||||||
|
|
||||||
|
export async function GET() {
|
||||||
|
try {
|
||||||
|
(await cookies()).set({
|
||||||
|
name: 'access_token',
|
||||||
|
value: '',
|
||||||
|
httpOnly: true,
|
||||||
|
secure: true,
|
||||||
|
sameSite: 'strict',
|
||||||
|
path: '/',
|
||||||
|
domain: process.env.COOKIE_DOMAIN,
|
||||||
|
maxAge: -1,
|
||||||
|
});
|
||||||
|
|
||||||
|
return NextResponse.json({message: 'Deleted access token'});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in /api/untoken:', error);
|
||||||
|
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
||||||
8
webui/src/lib/api.js
Normal file
8
webui/src/lib/api.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
const api = axios.create({
|
||||||
|
baseURL: process.env.NEXT_PUBLIC_API_URL,
|
||||||
|
withCredentials: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default api;
|
||||||
Reference in New Issue
Block a user