diff --git a/src/Application/Common/Interfaces/IApplicationDbContext.cs b/src/Application/Common/Interfaces/IApplicationDbContext.cs index d393e32..d385ede 100644 --- a/src/Application/Common/Interfaces/IApplicationDbContext.cs +++ b/src/Application/Common/Interfaces/IApplicationDbContext.cs @@ -17,6 +17,7 @@ public interface IApplicationDbContext DbSet Chapters { get; } DbSet UsersCourses { get; } + DbSet WishlistItems { get; } Task SaveChangesAsync(CancellationToken cancellationToken); } diff --git a/src/Application/Features/Courses/Commands/AddCourseUserWL/AddCourseUserWL.cs b/src/Application/Features/Courses/Commands/AddCourseUserWL/AddCourseUserWL.cs new file mode 100644 index 0000000..93890a6 --- /dev/null +++ b/src/Application/Features/Courses/Commands/AddCourseUserWL/AddCourseUserWL.cs @@ -0,0 +1,24 @@ +using SkillSphere.Application.Common.Interfaces; +using SkillSphere.Domain.Entities; + +namespace SkillSphere.Application.Features.Courses.Commands.AddCourseUserWL; + +public record AddCourseUserWLCommand(Guid UserId, Guid CourseId) : IRequest; + +public class AddCourseUserWLCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public AddCourseUserWLCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(AddCourseUserWLCommand request, CancellationToken cancellationToken) + { + var newWishlistItem = new WishListItem { UserId = request.UserId, CourseId = request.CourseId, }; + + _context.WishlistItems.Add(newWishlistItem); + await _context.SaveChangesAsync(cancellationToken); + } +} diff --git a/src/Application/Features/Courses/Commands/AddCourseUserWL/CourseWishListCommand.cs b/src/Application/Features/Courses/Commands/AddCourseUserWL/CourseWishListCommand.cs new file mode 100644 index 0000000..6394f32 --- /dev/null +++ b/src/Application/Features/Courses/Commands/AddCourseUserWL/CourseWishListCommand.cs @@ -0,0 +1,7 @@ +namespace SkillSphere.Application.Features.Courses.Commands.AddCourseUserWL; + +public class CourseWishListCommand : IRequest +{ + public Guid CourseId { get; init; } + public Guid UserId { get; init; } +} diff --git a/src/Application/Features/Courses/Commands/DecreaseLike/DecreaseLike.cs b/src/Application/Features/Courses/Commands/DecreaseLike/DecreaseLike.cs new file mode 100644 index 0000000..276706f --- /dev/null +++ b/src/Application/Features/Courses/Commands/DecreaseLike/DecreaseLike.cs @@ -0,0 +1,28 @@ +using SkillSphere.Application.Common.Interfaces; + +namespace SkillSphere.Application.Features.Courses.Commands.DecreaseLike; + +public record DecreaseLikeCountCommand(Guid CourseId) : IRequest; + +public class DecreaseLikeCountCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public DecreaseLikeCountCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(DecreaseLikeCountCommand request, CancellationToken cancellationToken) + { + var course = await _context.Courses.FindAsync(request.CourseId); + + Guard.Against.NotFound(request.CourseId, course); + + if (course.Likes > 0) + { + course.Likes--; + await _context.SaveChangesAsync(cancellationToken); + } + } +} diff --git a/src/Application/Features/Courses/Commands/IncreaseLikes/IncreaseLikes.cs b/src/Application/Features/Courses/Commands/IncreaseLikes/IncreaseLikes.cs new file mode 100644 index 0000000..2a59206 --- /dev/null +++ b/src/Application/Features/Courses/Commands/IncreaseLikes/IncreaseLikes.cs @@ -0,0 +1,26 @@ +using SkillSphere.Application.Common.Interfaces; + +namespace SkillSphere.Application.Features.Courses.Commands.IncreaseLikes; + +public record IncreaseLikesCommand(Guid CourseId) : IRequest; + +public class IncreaseLikesCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public IncreaseLikesCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(IncreaseLikesCommand request, CancellationToken cancellationToken) + { + var course = await _context.Courses.FindAsync(request.CourseId); + + Guard.Against.NotFound(request.CourseId, course); + + course.Likes++; + await _context.SaveChangesAsync(cancellationToken); + } +} + diff --git a/src/Application/Features/Courses/Commands/RemoveCourseWL/RemoveCourseWL.cs b/src/Application/Features/Courses/Commands/RemoveCourseWL/RemoveCourseWL.cs new file mode 100644 index 0000000..ef0a772 --- /dev/null +++ b/src/Application/Features/Courses/Commands/RemoveCourseWL/RemoveCourseWL.cs @@ -0,0 +1,30 @@ +using SkillSphere.Application.Common.Interfaces; +using SkillSphere.Application.TodoLists.Commands.DeleteTodoList; + +namespace SkillSphere.Application.Features.Courses.Commands.RemoveCourseWL; + +public record RemoveCourseWLCommand(Guid CourseId,Guid UserId) : IRequest; + +public class RemoveCourseWLCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public RemoveCourseWLCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(RemoveCourseWLCommand request, CancellationToken cancellationToken) + { + var wishlistItem = await _context.WishlistItems + .Where(l => l.UserId == request.UserId && l.CourseId == request.CourseId) + .SingleOrDefaultAsync(cancellationToken); + + Guard.Against.NotFound(request.CourseId, wishlistItem); + + _context.WishlistItems.Remove(wishlistItem); + + await _context.SaveChangesAsync(cancellationToken); + } +} + diff --git a/src/Application/Features/Courses/Queries/GetAllCourses/QueryDto.cs b/src/Application/Features/Courses/Queries/GetAllCourses/QueryDto.cs index 1bca33c..685f104 100644 --- a/src/Application/Features/Courses/Queries/GetAllCourses/QueryDto.cs +++ b/src/Application/Features/Courses/Queries/GetAllCourses/QueryDto.cs @@ -10,10 +10,11 @@ public class QueryDto public string? CoverImageRelativePath { get; set; } public bool IsPublished { get; set; } public float Price { get; set; } + public int Likes { get; set; } + public string? AuthorName { get; set; } public IReadOnlyCollection Categories { get; set; } public IReadOnlyCollection Chapters { get; init; } - public string? AuthorName { get; set; } public QueryDto() { diff --git a/src/Application/Features/Courses/Queries/GetCoursesForUser/GetCoursesForUser.cs b/src/Application/Features/Courses/Queries/GetCoursesForUser/GetCoursesForUser.cs index f847a30..5b3ba10 100644 --- a/src/Application/Features/Courses/Queries/GetCoursesForUser/GetCoursesForUser.cs +++ b/src/Application/Features/Courses/Queries/GetCoursesForUser/GetCoursesForUser.cs @@ -27,7 +27,7 @@ public async Task Handle(GetCourseByUsedIdQuery request, Cancellati .AsNoTracking() .Include(c => c.Categories) .Include(c => c.Chapters) - .Where(c => c.UserCourses.Any(uc => uc.UserId == userId)) // Filter courses for the specified user + .Where(c => c.UserCourses.Any(uc => uc.UserId == userId)) .ProjectTo(_mapper.ConfigurationProvider) .OrderBy(t => t.Title) .ToListAsync(cancellationToken) diff --git a/src/Application/Features/Courses/Queries/GetUserWishList/GetUserWishListQuery.cs b/src/Application/Features/Courses/Queries/GetUserWishList/GetUserWishListQuery.cs new file mode 100644 index 0000000..4abc929 --- /dev/null +++ b/src/Application/Features/Courses/Queries/GetUserWishList/GetUserWishListQuery.cs @@ -0,0 +1,45 @@ +using SkillSphere.Application.Common.Interfaces; +using SkillSphere.Application.Features.Courses.Queries.GetAllCourses; + +namespace SkillSphere.Application.Features.Courses.Queries; + +public class GetUserWishListQuery : IRequest +{ + public Guid UserId { get; init; } +} + + +public class GetUserWishListQueryHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + private readonly IMapper _mapper; + + public GetUserWishListQueryHandler(IApplicationDbContext context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + public async Task Handle(GetUserWishListQuery request, CancellationToken cancellationToken) + { + + Guid userId = request.UserId; + + + + return new GetCourseVm + { + Courses = await _context.Courses + .AsNoTracking() + .Include(c => c.Categories) + .Include(c => c.Chapters) + .Where(c => c.WishList.Any(wi => wi.UserId == userId)) + .ProjectTo(_mapper.ConfigurationProvider) + .OrderBy(t => t.Title) + .ToListAsync(cancellationToken) + }; + + } +} + + diff --git a/src/Domain/Entities/ApplicationUser.cs b/src/Domain/Entities/ApplicationUser.cs index b82508e..49e020b 100644 --- a/src/Domain/Entities/ApplicationUser.cs +++ b/src/Domain/Entities/ApplicationUser.cs @@ -5,4 +5,5 @@ namespace SkillSphere.Domain.Entities; public class ApplicationUser : IdentityUser { public IList? UserCourses { get; set; } + public IList? WishList { get; init; } = new List(); } diff --git a/src/Domain/Entities/Course.cs b/src/Domain/Entities/Course.cs index 7440c09..6bdeffd 100644 --- a/src/Domain/Entities/Course.cs +++ b/src/Domain/Entities/Course.cs @@ -8,10 +8,14 @@ public class Course : BaseAuditableEntity public bool? IsPublished { get; set; } = false; public float Price { get; set; } + + public int Likes { get; set; } = 0; public IList Chapters { get; init; } = new List(); public IList Categories { get; init; } = new List(); public IList UserCourses { get; init; } = new List(); + + public IList WishList { get; init; } = new List(); } diff --git a/src/Domain/Entities/UserCourse.cs b/src/Domain/Entities/UserCourse.cs index c0f7aa7..62f8b0d 100644 --- a/src/Domain/Entities/UserCourse.cs +++ b/src/Domain/Entities/UserCourse.cs @@ -13,16 +13,3 @@ public class UserCourse public Course? Course { get; set; } } -// STUFF I HAVE TO DO AND WHAT IS WRONG - -// STRUCTURE -// - appUser is in infrastructure -// - userCourse is in Domain -// - appUser cannot be referenced from Domain/Entity -// - cannot use interface and implement it into appUser class in order to -// use it inside the Domain -// - clean architecture -// - vertical slices -// - dbContext -// - Application layer for having the interface of email sender and send it from infrastructure - diff --git a/src/Domain/Entities/WishListItem.cs b/src/Domain/Entities/WishListItem.cs new file mode 100644 index 0000000..6a99406 --- /dev/null +++ b/src/Domain/Entities/WishListItem.cs @@ -0,0 +1,10 @@ +namespace SkillSphere.Domain.Entities; + +public class WishListItem +{ + public Guid UserId { get; set; } + public ApplicationUser? User { get; set; } + + public Guid CourseId { get; set; } + public Course? Course { get; set; } +} diff --git a/src/Infrastructure/Data/ApplicationDbContext.cs b/src/Infrastructure/Data/ApplicationDbContext.cs index 1d2b28d..14ddd08 100644 --- a/src/Infrastructure/Data/ApplicationDbContext.cs +++ b/src/Infrastructure/Data/ApplicationDbContext.cs @@ -27,6 +27,7 @@ public ApplicationDbContext(DbContextOptions options) : ba public DbSet Chapters => Set(); public DbSet UsersCourses => Set(); + public DbSet WishlistItems => Set(); protected override void OnModelCreating(ModelBuilder builder) diff --git a/src/Infrastructure/Data/ApplicationDbContextInitialiser.cs b/src/Infrastructure/Data/ApplicationDbContextInitialiser.cs index a87b576..8d2a151 100644 --- a/src/Infrastructure/Data/ApplicationDbContextInitialiser.cs +++ b/src/Infrastructure/Data/ApplicationDbContextInitialiser.cs @@ -103,6 +103,7 @@ public async Task TrySeedAsync() Description = "Course 1 Description", CoverImageRelativePath = "https://images.pexels.com/photos/693859/pexels-photo-693859.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1", Price = 9.99f, + Likes = 0, Categories = new List { new CourseCategory diff --git a/src/Infrastructure/Data/Configurations/WishListItemConfiguration.cs b/src/Infrastructure/Data/Configurations/WishListItemConfiguration.cs new file mode 100644 index 0000000..508becb --- /dev/null +++ b/src/Infrastructure/Data/Configurations/WishListItemConfiguration.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using SkillSphere.Domain.Entities; + +namespace SkillSphere.Infrastructure.Data.Configurations; + +public class WishListItemConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder + .HasKey(wi => new { wi.UserId, wi.CourseId }); + + builder + .HasOne(wi => wi.User) + .WithMany(u => u.WishList) + .HasForeignKey(wi => wi.UserId); + + builder + .HasOne(wi => wi.Course) + .WithMany(c => c.WishList) + .HasForeignKey(wi => wi.CourseId); + } + +} + + + + diff --git a/src/Infrastructure/Data/Migrations/20231203160959_Likes.Designer.cs b/src/Infrastructure/Data/Migrations/20231203160959_Likes.Designer.cs new file mode 100644 index 0000000..183b7c6 --- /dev/null +++ b/src/Infrastructure/Data/Migrations/20231203160959_Likes.Designer.cs @@ -0,0 +1,527 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using skillSphere.Infrastructure.Data; + +#nullable disable + +namespace SkillSphere.Infrastructure.Data.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20231203160959_Likes")] + partial class Likes + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.ApplicationRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.ApplicationUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.Category", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Categories"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CourseId") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("IsFree") + .HasColumnType("bit"); + + b.Property("Position") + .HasColumnType("int"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.Property("VideoURL") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CourseId"); + + b.ToTable("Chapters"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.Course", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CoverImageRelativePath") + .HasColumnType("nvarchar(max)"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("IsPublished") + .HasColumnType("bit"); + + b.Property("Likes") + .HasColumnType("int"); + + b.Property("Price") + .HasColumnType("real"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Courses"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.CourseCategory", b => + { + b.Property("CourseId") + .HasColumnType("uniqueidentifier"); + + b.Property("CategoryId") + .HasColumnType("uniqueidentifier"); + + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.HasKey("CourseId", "CategoryId"); + + b.HasIndex("CategoryId"); + + b.ToTable("CourseCategories"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.TodoItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("ListId") + .HasColumnType("uniqueidentifier"); + + b.Property("Note") + .HasColumnType("nvarchar(max)"); + + b.Property("Reminder") + .HasColumnType("datetime2"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.HasIndex("ListId"); + + b.ToTable("TodoItems"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.TodoList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("TodoLists"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.UserCourse", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("CourseId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("UserId", "CourseId"); + + b.HasIndex("CourseId"); + + b.ToTable("UsersCourses"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("SkillSphere.Domain.Entities.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("SkillSphere.Domain.Entities.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("SkillSphere.Domain.Entities.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("SkillSphere.Domain.Entities.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SkillSphere.Domain.Entities.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("SkillSphere.Domain.Entities.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.Chapter", b => + { + b.HasOne("SkillSphere.Domain.Entities.Course", "Course") + .WithMany("Chapters") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Course"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.CourseCategory", b => + { + b.HasOne("SkillSphere.Domain.Entities.Category", "Category") + .WithMany("CourseCategories") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SkillSphere.Domain.Entities.Course", "Course") + .WithMany("Categories") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Category"); + + b.Navigation("Course"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.TodoItem", b => + { + b.HasOne("SkillSphere.Domain.Entities.TodoList", "List") + .WithMany("Items") + .HasForeignKey("ListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("List"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.UserCourse", b => + { + b.HasOne("SkillSphere.Domain.Entities.Course", "Course") + .WithMany("UserCourses") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SkillSphere.Domain.Entities.ApplicationUser", "User") + .WithMany("UserCourses") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Course"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.ApplicationUser", b => + { + b.Navigation("UserCourses"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.Category", b => + { + b.Navigation("CourseCategories"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.Course", b => + { + b.Navigation("Categories"); + + b.Navigation("Chapters"); + + b.Navigation("UserCourses"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.TodoList", b => + { + b.Navigation("Items"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Infrastructure/Data/Migrations/20231203160959_Likes.cs b/src/Infrastructure/Data/Migrations/20231203160959_Likes.cs new file mode 100644 index 0000000..1998b67 --- /dev/null +++ b/src/Infrastructure/Data/Migrations/20231203160959_Likes.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace SkillSphere.Infrastructure.Data.Migrations +{ + /// + public partial class Likes : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Likes", + table: "Courses", + type: "int", + nullable: false, + defaultValue: 0); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Likes", + table: "Courses"); + } + } +} diff --git a/src/Infrastructure/Data/Migrations/20231203165033_Wish.Designer.cs b/src/Infrastructure/Data/Migrations/20231203165033_Wish.Designer.cs new file mode 100644 index 0000000..9ffb085 --- /dev/null +++ b/src/Infrastructure/Data/Migrations/20231203165033_Wish.Designer.cs @@ -0,0 +1,565 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using skillSphere.Infrastructure.Data; + +#nullable disable + +namespace SkillSphere.Infrastructure.Data.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20231203165033_Wish")] + partial class Wish + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.ApplicationRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.ApplicationUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.Category", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Categories"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CourseId") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("IsFree") + .HasColumnType("bit"); + + b.Property("Position") + .HasColumnType("int"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.Property("VideoURL") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CourseId"); + + b.ToTable("Chapters"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.Course", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CoverImageRelativePath") + .HasColumnType("nvarchar(max)"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("IsPublished") + .HasColumnType("bit"); + + b.Property("Likes") + .HasColumnType("int"); + + b.Property("Price") + .HasColumnType("real"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Courses"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.CourseCategory", b => + { + b.Property("CourseId") + .HasColumnType("uniqueidentifier"); + + b.Property("CategoryId") + .HasColumnType("uniqueidentifier"); + + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.HasKey("CourseId", "CategoryId"); + + b.HasIndex("CategoryId"); + + b.ToTable("CourseCategories"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.TodoItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("ListId") + .HasColumnType("uniqueidentifier"); + + b.Property("Note") + .HasColumnType("nvarchar(max)"); + + b.Property("Reminder") + .HasColumnType("datetime2"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.HasIndex("ListId"); + + b.ToTable("TodoItems"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.TodoList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("TodoLists"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.UserCourse", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("CourseId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("UserId", "CourseId"); + + b.HasIndex("CourseId"); + + b.ToTable("UsersCourses"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.WishListItem", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("CourseId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("UserId", "CourseId"); + + b.HasIndex("CourseId"); + + b.ToTable("WishlistItems"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("SkillSphere.Domain.Entities.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("SkillSphere.Domain.Entities.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("SkillSphere.Domain.Entities.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("SkillSphere.Domain.Entities.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SkillSphere.Domain.Entities.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("SkillSphere.Domain.Entities.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.Chapter", b => + { + b.HasOne("SkillSphere.Domain.Entities.Course", "Course") + .WithMany("Chapters") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Course"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.CourseCategory", b => + { + b.HasOne("SkillSphere.Domain.Entities.Category", "Category") + .WithMany("CourseCategories") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SkillSphere.Domain.Entities.Course", "Course") + .WithMany("Categories") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Category"); + + b.Navigation("Course"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.TodoItem", b => + { + b.HasOne("SkillSphere.Domain.Entities.TodoList", "List") + .WithMany("Items") + .HasForeignKey("ListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("List"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.UserCourse", b => + { + b.HasOne("SkillSphere.Domain.Entities.Course", "Course") + .WithMany("UserCourses") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SkillSphere.Domain.Entities.ApplicationUser", "User") + .WithMany("UserCourses") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Course"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.WishListItem", b => + { + b.HasOne("SkillSphere.Domain.Entities.Course", "Course") + .WithMany("WishList") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SkillSphere.Domain.Entities.ApplicationUser", "User") + .WithMany("WishList") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Course"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.ApplicationUser", b => + { + b.Navigation("UserCourses"); + + b.Navigation("WishList"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.Category", b => + { + b.Navigation("CourseCategories"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.Course", b => + { + b.Navigation("Categories"); + + b.Navigation("Chapters"); + + b.Navigation("UserCourses"); + + b.Navigation("WishList"); + }); + + modelBuilder.Entity("SkillSphere.Domain.Entities.TodoList", b => + { + b.Navigation("Items"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Infrastructure/Data/Migrations/20231203165033_Wish.cs b/src/Infrastructure/Data/Migrations/20231203165033_Wish.cs new file mode 100644 index 0000000..a6c276a --- /dev/null +++ b/src/Infrastructure/Data/Migrations/20231203165033_Wish.cs @@ -0,0 +1,51 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace SkillSphere.Infrastructure.Data.Migrations +{ + /// + public partial class Wish : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "WishlistItems", + columns: table => new + { + UserId = table.Column(type: "uniqueidentifier", nullable: false), + CourseId = table.Column(type: "uniqueidentifier", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_WishlistItems", x => new { x.UserId, x.CourseId }); + table.ForeignKey( + name: "FK_WishlistItems_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_WishlistItems_Courses_CourseId", + column: x => x.CourseId, + principalTable: "Courses", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_WishlistItems_CourseId", + table: "WishlistItems", + column: "CourseId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "WishlistItems"); + } + } +} diff --git a/src/Infrastructure/Data/Migrations/ApplicationDbContextModelSnapshot.cs b/src/Infrastructure/Data/Migrations/ApplicationDbContextModelSnapshot.cs index 47e1bd7..2fa95b1 100644 --- a/src/Infrastructure/Data/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/src/Infrastructure/Data/Migrations/ApplicationDbContextModelSnapshot.cs @@ -286,6 +286,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("IsPublished") .HasColumnType("bit"); + b.Property("Likes") + .HasColumnType("int"); + b.Property("Price") .HasColumnType("real"); @@ -381,6 +384,21 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("UsersCourses"); }); + modelBuilder.Entity("SkillSphere.Domain.Entities.WishListItem", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("CourseId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("UserId", "CourseId"); + + b.HasIndex("CourseId"); + + b.ToTable("WishlistItems"); + }); + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => { b.HasOne("SkillSphere.Domain.Entities.ApplicationRole", null) @@ -492,9 +510,30 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("User"); }); + modelBuilder.Entity("SkillSphere.Domain.Entities.WishListItem", b => + { + b.HasOne("SkillSphere.Domain.Entities.Course", "Course") + .WithMany("WishList") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SkillSphere.Domain.Entities.ApplicationUser", "User") + .WithMany("WishList") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Course"); + + b.Navigation("User"); + }); + modelBuilder.Entity("SkillSphere.Domain.Entities.ApplicationUser", b => { b.Navigation("UserCourses"); + + b.Navigation("WishList"); }); modelBuilder.Entity("SkillSphere.Domain.Entities.Category", b => @@ -509,6 +548,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Chapters"); b.Navigation("UserCourses"); + + b.Navigation("WishList"); }); modelBuilder.Entity("SkillSphere.Domain.Entities.TodoList", b => diff --git a/src/UI/src/app/core/auth/service/user.service.ts b/src/UI/src/app/core/auth/service/user.service.ts new file mode 100644 index 0000000..6362a19 --- /dev/null +++ b/src/UI/src/app/core/auth/service/user.service.ts @@ -0,0 +1,53 @@ +import {Injectable, OnDestroy, inject} from '@angular/core'; +import {HttpClient, HttpResponse} from '@angular/common/http'; +import {environment} from '../../../../environments/environment'; +import { shareReplay } from 'rxjs/operators'; +import { tap } from 'rxjs/operators'; +import {BehaviorSubject, Observable, Observer} from 'rxjs'; +import { AuthResponse } from '../models/login'; +import { Register } from '../models/register'; +import { Course } from 'src/app/modules/management/models/course'; +import { AuthService } from './auth.service'; + +@Injectable({ + providedIn: 'root' +}) + +export class UserService { + + public wishList: Observable; + private _wishListState = new BehaviorSubject([]); + + constructor(private _http: HttpClient, private authService: AuthService) { + this.wishList = this._wishListState.asObservable(); + + const userId = this.authService.getUserId(); + + if (userId) { + this.loadWishList(userId); + } else { + + this._wishListState.next([]); + } + + + } + + private async loadWishList(userId: string) { + try { + const response = await this._http.get<{ courses: Course[] }>(`${environment.baseUrl}/courses/${userId}/wishlist`, { observe: 'response' }).toPromise(); + + if (response.ok) { + const wishlist = response.body.courses; + this._wishListState.next(wishlist); + } else { + this._wishListState.next([]); + } + } catch (error) { + console.error('HTTP request error:', error); + this._wishListState.next([]); + } + } + + + } \ No newline at end of file diff --git a/src/UI/src/app/modules/layout/components/sidebar/sidebar-menu/sidebar-menu.component.html b/src/UI/src/app/modules/layout/components/sidebar/sidebar-menu/sidebar-menu.component.html index 4cd7f08..13f457a 100644 --- a/src/UI/src/app/modules/layout/components/sidebar/sidebar-menu/sidebar-menu.component.html +++ b/src/UI/src/app/modules/layout/components/sidebar/sidebar-menu/sidebar-menu.component.html @@ -13,9 +13,9 @@
- +
@@ -30,7 +30,7 @@ class="flex h-9 cursor-pointer items-center justify-start rounded text-gray-600 hover:bg-gray-100 dark:text-night-100 dark:hover:bg-night-600"> {{ item.label }} diff --git a/src/UI/src/app/modules/layout/components/sidebar/sidebar.component.html b/src/UI/src/app/modules/layout/components/sidebar/sidebar.component.html index a3a6a16..801727a 100644 --- a/src/UI/src/app/modules/layout/components/sidebar/sidebar.component.html +++ b/src/UI/src/app/modules/layout/components/sidebar/sidebar.component.html @@ -1,6 +1,7 @@