diff --git a/backend/.vs/VSWorkspaceState.json b/backend/.vs/VSWorkspaceState.json
new file mode 100644
index 00000000..51c17612
--- /dev/null
+++ b/backend/.vs/VSWorkspaceState.json
@@ -0,0 +1,9 @@
+{
+ "ExpandedNodes": [
+ "",
+ "\\BackendAssessment",
+ "\\BackendAssessment\\Infrastructure"
+ ],
+ "SelectedNode": "\\BackendAssessment\\Infrastructure\\Infrastructure.csproj",
+ "PreviewInSolutionExplorer": false
+}
\ No newline at end of file
diff --git a/backend/.vs/backend/FileContentIndex/504a1ad5-97ec-4b59-b934-3f782a787b96.vsidx b/backend/.vs/backend/FileContentIndex/504a1ad5-97ec-4b59-b934-3f782a787b96.vsidx
new file mode 100644
index 00000000..54e0e050
Binary files /dev/null and b/backend/.vs/backend/FileContentIndex/504a1ad5-97ec-4b59-b934-3f782a787b96.vsidx differ
diff --git a/backend/.vs/backend/FileContentIndex/a5562604-b092-4b27-ba22-b36b38cf0958.vsidx b/backend/.vs/backend/FileContentIndex/a5562604-b092-4b27-ba22-b36b38cf0958.vsidx
new file mode 100644
index 00000000..96eaf11f
Binary files /dev/null and b/backend/.vs/backend/FileContentIndex/a5562604-b092-4b27-ba22-b36b38cf0958.vsidx differ
diff --git a/backend/.vs/backend/FileContentIndex/read.lock b/backend/.vs/backend/FileContentIndex/read.lock
new file mode 100644
index 00000000..e69de29b
diff --git a/backend/.vs/backend/v17/.wsuo b/backend/.vs/backend/v17/.wsuo
new file mode 100644
index 00000000..4cef5b2b
Binary files /dev/null and b/backend/.vs/backend/v17/.wsuo differ
diff --git a/backend/.vs/slnx.sqlite b/backend/.vs/slnx.sqlite
new file mode 100644
index 00000000..6c45b45e
Binary files /dev/null and b/backend/.vs/slnx.sqlite differ
diff --git a/backend/BackendAssessment/Application.Tests/Application.Tests.csproj b/backend/BackendAssessment/Application.Tests/Application.Tests.csproj
index 37de39f4..e2907571 100644
--- a/backend/BackendAssessment/Application.Tests/Application.Tests.csproj
+++ b/backend/BackendAssessment/Application.Tests/Application.Tests.csproj
@@ -24,4 +24,8 @@
+
+
+
+
diff --git a/backend/BackendAssessment/Application/Application.csproj b/backend/BackendAssessment/Application/Application.csproj
index 9c452bbc..e22460aa 100644
--- a/backend/BackendAssessment/Application/Application.csproj
+++ b/backend/BackendAssessment/Application/Application.csproj
@@ -1,4 +1,4 @@
-
+
net7.0
@@ -7,10 +7,14 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/backend/BackendAssessment/Application/Contracts/ICategoryRepository.cs b/backend/BackendAssessment/Application/Contracts/ICategoryRepository.cs
new file mode 100644
index 00000000..c3e4db62
--- /dev/null
+++ b/backend/BackendAssessment/Application/Contracts/ICategoryRepository.cs
@@ -0,0 +1,14 @@
+using Domain.Entites;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Persistence.Repositories
+{
+ public interface ICategoryRepository : IGenericRepository
+ {
+
+ }
+}
diff --git a/backend/BackendAssessment/Application/Contracts/IGenericRepository.cs b/backend/BackendAssessment/Application/Contracts/IGenericRepository.cs
new file mode 100644
index 00000000..c2c3f0f9
--- /dev/null
+++ b/backend/BackendAssessment/Application/Contracts/IGenericRepository.cs
@@ -0,0 +1,20 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Persistence.Repositories
+{
+ public interface IGenericRepository where T : class
+ {
+ Task Get(Guid id);
+ Task> GetAll();
+ Task Add(T entity);
+ Task Update(T entity);
+ bool Exists(Guid Id);
+ void Delete(T entity);
+
+ }
+}
diff --git a/backend/BackendAssessment/Application/Contracts/IProductRepository.cs b/backend/BackendAssessment/Application/Contracts/IProductRepository.cs
new file mode 100644
index 00000000..6a5a153f
--- /dev/null
+++ b/backend/BackendAssessment/Application/Contracts/IProductRepository.cs
@@ -0,0 +1,15 @@
+using Domain.Entites;
+using Persistence.Repositories;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.Contracts
+{
+ public interface IProductRepository : IGenericRepository
+ {
+
+ }
+}
diff --git a/backend/BackendAssessment/Application/Contracts/IUserRepository.cs b/backend/BackendAssessment/Application/Contracts/IUserRepository.cs
new file mode 100644
index 00000000..5839ed19
--- /dev/null
+++ b/backend/BackendAssessment/Application/Contracts/IUserRepository.cs
@@ -0,0 +1,14 @@
+using Domain.Entites;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Persistence.Repositories
+{
+ public interface IUserRepository : IGenericRepository
+ {
+
+ }
+}
diff --git a/backend/BackendAssessment/Application/DTOs/Category/CategoryRetriveDto.cs b/backend/BackendAssessment/Application/DTOs/Category/CategoryRetriveDto.cs
new file mode 100644
index 00000000..433c68b4
--- /dev/null
+++ b/backend/BackendAssessment/Application/DTOs/Category/CategoryRetriveDto.cs
@@ -0,0 +1,14 @@
+using Application.DTOs.Common;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.DTOs.Category
+{
+ public class CategoryRetriveDto : BaseEntityDto
+ {
+
+ }
+}
diff --git a/backend/BackendAssessment/Application/DTOs/Category/CreateCategoryDto.cs b/backend/BackendAssessment/Application/DTOs/Category/CreateCategoryDto.cs
new file mode 100644
index 00000000..b076109f
--- /dev/null
+++ b/backend/BackendAssessment/Application/DTOs/Category/CreateCategoryDto.cs
@@ -0,0 +1,14 @@
+using Application.DTOs.Common;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.DTOs.Category
+{
+ public class CreateCategoryDto : BaseEntityDto
+ {
+
+ }
+}
diff --git a/backend/BackendAssessment/Application/DTOs/Common/BaseEntityDto.cs b/backend/BackendAssessment/Application/DTOs/Common/BaseEntityDto.cs
new file mode 100644
index 00000000..f85c00a4
--- /dev/null
+++ b/backend/BackendAssessment/Application/DTOs/Common/BaseEntityDto.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.DTOs.Common
+{
+ public class BaseEntityDto
+ {
+ public int Id { get; set; }
+ public string name { get; set; }
+ public string description { get; set; }
+
+ }
+}
diff --git a/backend/BackendAssessment/Application/DTOs/Product/CreateProductDTO.cs b/backend/BackendAssessment/Application/DTOs/Product/CreateProductDTO.cs
new file mode 100644
index 00000000..d627a251
--- /dev/null
+++ b/backend/BackendAssessment/Application/DTOs/Product/CreateProductDTO.cs
@@ -0,0 +1,15 @@
+using Application.DTOs.Common;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.DTOs.Product
+{
+ public class CreateProductDTO : BaseEntityDto
+ {
+ public bool isAvailable { get; set; }
+ public double pricing { get; set; }
+ }
+}
diff --git a/backend/BackendAssessment/Application/DTOs/Product/UpdateProductDto.cs b/backend/BackendAssessment/Application/DTOs/Product/UpdateProductDto.cs
new file mode 100644
index 00000000..0fe003df
--- /dev/null
+++ b/backend/BackendAssessment/Application/DTOs/Product/UpdateProductDto.cs
@@ -0,0 +1,15 @@
+using Application.DTOs.Common;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.DTOs.Product
+{
+ public class UpdateProductDto : BaseEntityDto
+ {
+ public bool isAvailable { get; set; }
+ public double pricing { get; set; }
+ }
+}
diff --git a/backend/BackendAssessment/Application/DTOs/Product/Validator/CreateProductDtoValidator.cs b/backend/BackendAssessment/Application/DTOs/Product/Validator/CreateProductDtoValidator.cs
new file mode 100644
index 00000000..08bbcda9
--- /dev/null
+++ b/backend/BackendAssessment/Application/DTOs/Product/Validator/CreateProductDtoValidator.cs
@@ -0,0 +1,28 @@
+using FluentValidation;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.DTOs.Product.Validator
+{
+ public class CreateProductDtoValidator : AbstractValidator
+ {
+ public CreateProductDtoValidator()
+ {
+ RuleFor(dto => dto.name)
+ .NotEmpty()
+ .WithMessage("name is required.");
+
+ RuleFor(dto => dto.description)
+ .NotEmpty()
+ .WithMessage("Reciever description is required.");
+
+ RuleFor(dto => dto.pricing)
+ .NotEmpty()
+ .WithMessage("price is required.");
+ }
+
+ }
+}
diff --git a/backend/BackendAssessment/Application/DTOs/Product/productRetrieveDTO.cs b/backend/BackendAssessment/Application/DTOs/Product/productRetrieveDTO.cs
new file mode 100644
index 00000000..34b26a9b
--- /dev/null
+++ b/backend/BackendAssessment/Application/DTOs/Product/productRetrieveDTO.cs
@@ -0,0 +1,19 @@
+using Application.DTOs.Category;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.DTOs.Product
+{
+ public class productRetrieveDTO
+ {
+ public string name { get; set; }
+ public string description { get; set; }
+ public string availability { get; set; }
+ public string pricing { get; set; }
+ public CategoryRetriveDto category { get; set; }
+
+ }
+}
diff --git a/backend/BackendAssessment/Application/DTOs/User/CreateUserDto.cs b/backend/BackendAssessment/Application/DTOs/User/CreateUserDto.cs
new file mode 100644
index 00000000..9d7475c2
--- /dev/null
+++ b/backend/BackendAssessment/Application/DTOs/User/CreateUserDto.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.DTOs.User
+{
+ public class CreateUserDto
+ {
+ public string username { get; set; }
+ public string password { get; set; }
+ public string email { get; set; }
+ public bool isAdmin { get; set; }
+
+ }
+}
diff --git a/backend/BackendAssessment/Application/DTOs/User/Validator/CreateUserDtoValidator.cs b/backend/BackendAssessment/Application/DTOs/User/Validator/CreateUserDtoValidator.cs
new file mode 100644
index 00000000..7210e90f
--- /dev/null
+++ b/backend/BackendAssessment/Application/DTOs/User/Validator/CreateUserDtoValidator.cs
@@ -0,0 +1,28 @@
+using FluentValidation;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.DTOs.User.Validator
+{
+ public class CreateUserDtoValidator : AbstractValidator
+ {
+ public CreateUserDtoValidator() {
+
+ RuleFor(dto => dto.username)
+ .NotEmpty()
+ .WithMessage("name is required.");
+
+ RuleFor(dto => dto.email)
+ .NotEmpty()
+ .WithMessage("email is required.");
+
+ RuleFor(dto => dto.password)
+ .NotEmpty()
+ .WithMessage("password is required.");
+
+ }
+ }
+}
diff --git a/backend/BackendAssessment/Application/Features/Categories/Handler/Command/CreateCategoryCommandHandler.cs b/backend/BackendAssessment/Application/Features/Categories/Handler/Command/CreateCategoryCommandHandler.cs
new file mode 100644
index 00000000..3bec065d
--- /dev/null
+++ b/backend/BackendAssessment/Application/Features/Categories/Handler/Command/CreateCategoryCommandHandler.cs
@@ -0,0 +1,36 @@
+using Application.DTOs.Category;
+using Application.Features.Categories.Request.Command;
+using AutoMapper;
+using MediatR;
+using Persistence.Repositories;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Domain.Entites;
+
+namespace Application.Features.Categories.Handler.Command
+{
+ public class CreateCategoryCommandHandler : IRequestHandler
+ {
+ private readonly ICategoryRepository _categoryRepository;
+ private readonly IMapper _mapper;
+
+ public CreateCategoryCommandHandler(ICategoryRepository i, IMapper mapper)
+ {
+ _categoryRepository = i;
+ _mapper = mapper;
+ }
+
+ public async Task Handle(CreateCategoryCommand request, CancellationToken cancellationToken)
+ {
+ var category = _mapper.Map(request);
+ var result = await _categoryRepository.Add(category);
+
+ var response = _mapper.Map(result);
+ return response;
+ }
+ }
+}
+
diff --git a/backend/BackendAssessment/Application/Features/Categories/Handler/Command/UpdateCategoryCommandHandler.cs b/backend/BackendAssessment/Application/Features/Categories/Handler/Command/UpdateCategoryCommandHandler.cs
new file mode 100644
index 00000000..0d1ecb85
--- /dev/null
+++ b/backend/BackendAssessment/Application/Features/Categories/Handler/Command/UpdateCategoryCommandHandler.cs
@@ -0,0 +1,42 @@
+using Application.DTOs.Category;
+using Application.Features.Categories.Request.Command;
+using AutoMapper;
+using Domain.Entites;
+using MediatR;
+using Persistence.Repositories;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using static System.Runtime.InteropServices.JavaScript.JSType;
+
+namespace Application.Features.Categories.Handler.Command
+{
+ public class UpdateCategoryCommandHandler : IRequestHandler
+ {
+ private readonly ICategoryRepository _categoryRepository;
+ private readonly IMapper _mapper;
+
+ public UpdateCategoryCommandHandler(ICategoryRepository i, IMapper mapper)
+ {
+ _categoryRepository = i;
+ _mapper = mapper;
+ }
+
+ public async Task Handle(UpdateCategoryCommand request, CancellationToken cancellationToken)
+ {
+ var category = await _categoryRepository.Get(request.id)!;
+ if (category == null)
+ {
+ throw new Exception();
+ }
+
+ var categoryToUpdate = _mapper.Map(request, category );
+ var updatedCategory = await _categoryRepository.Update(categoryToUpdate);
+ return _mapper.Map(updatedCategory);
+ }
+
+
+ }
+}
diff --git a/backend/BackendAssessment/Application/Features/Categories/Handler/Queries/GetCategoryRequestHandler.cs b/backend/BackendAssessment/Application/Features/Categories/Handler/Queries/GetCategoryRequestHandler.cs
new file mode 100644
index 00000000..a07a7193
--- /dev/null
+++ b/backend/BackendAssessment/Application/Features/Categories/Handler/Queries/GetCategoryRequestHandler.cs
@@ -0,0 +1,46 @@
+using Application.DTOs.Category;
+using Application.Features.Categories.Request.Queries;
+using AutoMapper;
+using MediatR;
+using Persistence.Repositories;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using static System.Runtime.InteropServices.JavaScript.JSType;
+
+namespace Application.Features.Categories.Handler.Queries
+{
+ public class GetCategoryRequestHandler : IRequestHandler
+ {
+ private readonly ICategoryRepository _categoryRepository;
+ private readonly IMapper _mapper;
+
+ public GetCategoryRequestHandler(ICategoryRepository commentRepository, IMapper mapper)
+ {
+ _categoryRepository = commentRepository;
+ _mapper = mapper;
+ }
+
+
+
+
+ public async Task Handle(GetCategoryRequest request, CancellationToken cancellationToken)
+ {
+ var res = await _categoryRepository.Get(request.id)!;
+
+ if (res == null)
+ {
+ throw new Exception();
+ }
+
+ var categoryResponse = _mapper.Map(res);
+ return categoryResponse;
+ }
+
+
+ }
+
+
+}
diff --git a/backend/BackendAssessment/Application/Features/Categories/Request/Command/CreateCategoryCommand.cs b/backend/BackendAssessment/Application/Features/Categories/Request/Command/CreateCategoryCommand.cs
new file mode 100644
index 00000000..51ab9695
--- /dev/null
+++ b/backend/BackendAssessment/Application/Features/Categories/Request/Command/CreateCategoryCommand.cs
@@ -0,0 +1,16 @@
+using Application.DTOs.Category;
+using MediatR;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.Features.Categories.Request.Command
+{
+ public class CreateCategoryCommand : IRequest
+ {
+ public string name { get; set; }
+ public string description { get; set; }
+ }
+}
diff --git a/backend/BackendAssessment/Application/Features/Categories/Request/Command/UpdateCategoryCommand.cs b/backend/BackendAssessment/Application/Features/Categories/Request/Command/UpdateCategoryCommand.cs
new file mode 100644
index 00000000..293047c3
--- /dev/null
+++ b/backend/BackendAssessment/Application/Features/Categories/Request/Command/UpdateCategoryCommand.cs
@@ -0,0 +1,17 @@
+using Application.DTOs.Category;
+using MediatR;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.Features.Categories.Request.Command
+{
+ public class UpdateCategoryCommand : IRequest
+ {
+ public string name { get; set; }
+ public string description { get; set; }
+ public Guid id { get; set; }
+ }
+}
diff --git a/backend/BackendAssessment/Application/Features/Categories/Request/Queries/GetCategoryRequest.cs b/backend/BackendAssessment/Application/Features/Categories/Request/Queries/GetCategoryRequest.cs
new file mode 100644
index 00000000..94cdad37
--- /dev/null
+++ b/backend/BackendAssessment/Application/Features/Categories/Request/Queries/GetCategoryRequest.cs
@@ -0,0 +1,15 @@
+using Application.DTOs.Category;
+using MediatR;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.Features.Categories.Request.Queries
+{
+ public class GetCategoryRequest : IRequest
+ {
+ public Guid id { get; set; }
+ }
+}
diff --git a/backend/BackendAssessment/Application/Features/Products/Handler/Command/CreateProductCommandHandler.cs b/backend/BackendAssessment/Application/Features/Products/Handler/Command/CreateProductCommandHandler.cs
new file mode 100644
index 00000000..094850d7
--- /dev/null
+++ b/backend/BackendAssessment/Application/Features/Products/Handler/Command/CreateProductCommandHandler.cs
@@ -0,0 +1,37 @@
+using Application.Contracts;
+using Application.DTOs.Product;
+using Application.DTOs.User;
+using Application.Features.Products.Request.Command;
+using AutoMapper;
+using Domain.Entites;
+using MediatR;
+using Persistence.Repositories;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.Features.Products.Handler.Command
+{
+ public class CreateProductCommandHandler : IRequestHandler
+ {
+
+ private readonly IProductRepository _Repository;
+ private readonly IMapper _mapper;
+
+ public CreateProductCommandHandler(IProductRepository i, IMapper mapper)
+ {
+ _Repository = i;
+ _mapper = mapper;
+ }
+ public async Task Handle(CreateProductCommand request, CancellationToken cancellationToken)
+ {
+ var product = _mapper.Map(request);
+ var result = await _Repository.Add(product);
+
+ var response = _mapper.Map(result);
+ return response;
+ }
+ }
+}
diff --git a/backend/BackendAssessment/Application/Features/Products/Handler/Command/UpdateProductCommandHandler.cs b/backend/BackendAssessment/Application/Features/Products/Handler/Command/UpdateProductCommandHandler.cs
new file mode 100644
index 00000000..fbbe15b1
--- /dev/null
+++ b/backend/BackendAssessment/Application/Features/Products/Handler/Command/UpdateProductCommandHandler.cs
@@ -0,0 +1,39 @@
+using Application.Contracts;
+using Application.DTOs.Product;
+using Application.DTOs.User;
+using Application.Features.Products.Request.Command;
+using AutoMapper;
+using MediatR;
+using Persistence.Repositories;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.Features.Products.Handler.Command
+{
+ public class UpdateProductCommandHandler : IRequestHandler
+ {
+ private readonly IProductRepository _Repository;
+ private readonly IMapper _mapper;
+
+ public UpdateProductCommandHandler(IProductRepository i, IMapper mapper)
+ {
+ _Repository = i;
+ _mapper = mapper;
+ }
+ public async Task Handle(UpdateProductCommand request, CancellationToken cancellationToken)
+ {
+ var product = await _Repository.Get(request.id)!;
+ if (product == null)
+ {
+ throw new Exception();
+ }
+
+ var categoryToUpdate = _mapper.Map(request, product);
+ var updatedCategory = await _Repository.Update(categoryToUpdate);
+ return _mapper.Map(updatedCategory);
+ }
+ }
+}
diff --git a/backend/BackendAssessment/Application/Features/Products/Handler/Queries/GetProductRequestHandler.cs b/backend/BackendAssessment/Application/Features/Products/Handler/Queries/GetProductRequestHandler.cs
new file mode 100644
index 00000000..140008ae
--- /dev/null
+++ b/backend/BackendAssessment/Application/Features/Products/Handler/Queries/GetProductRequestHandler.cs
@@ -0,0 +1,39 @@
+using Application.Contracts;
+using Application.DTOs.Category;
+using Application.DTOs.Product;
+using Application.Features.Products.Request.Queries;
+using AutoMapper;
+using MediatR;
+using Persistence.Repositories;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.Features.Products.Handler.Queries
+{
+ public class GetProductRequestHandler : IRequestHandler
+ {
+ private readonly IProductRepository _Repository;
+ private readonly IMapper _mapper;
+
+ public GetProductRequestHandler(IProductRepository i, IMapper mapper)
+ {
+ _Repository = i;
+ _mapper = mapper;
+ }
+ public async Task Handle(GetProductRequest request, CancellationToken cancellationToken)
+ {
+ var res = await _Repository.Get(request.Id)!;
+
+ if (res == null)
+ {
+ throw new Exception();
+ }
+
+ var categoryResponse = _mapper.Map(res);
+ return categoryResponse;
+ }
+ }
+}
diff --git a/backend/BackendAssessment/Application/Features/Products/Request/Command/CreateProductCommand.cs b/backend/BackendAssessment/Application/Features/Products/Request/Command/CreateProductCommand.cs
new file mode 100644
index 00000000..3de38de7
--- /dev/null
+++ b/backend/BackendAssessment/Application/Features/Products/Request/Command/CreateProductCommand.cs
@@ -0,0 +1,18 @@
+using Application.DTOs.Product;
+using MediatR;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.Features.Products.Request.Command
+{
+ public class CreateProductCommand : IRequest
+ {
+ public string name { get; set; }
+ public string description { get; set; }
+ public double pricing { get; set; }
+ public bool IsAvailable { get; set; }
+ }
+}
diff --git a/backend/BackendAssessment/Application/Features/Products/Request/Command/UpdateProductCommand.cs b/backend/BackendAssessment/Application/Features/Products/Request/Command/UpdateProductCommand.cs
new file mode 100644
index 00000000..01517cc9
--- /dev/null
+++ b/backend/BackendAssessment/Application/Features/Products/Request/Command/UpdateProductCommand.cs
@@ -0,0 +1,19 @@
+using Application.DTOs.Product;
+using MediatR;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.Features.Products.Request.Command
+{
+ public class UpdateProductCommand : IRequest
+ {
+ public Guid id { get; set; }
+ public string name { get; set; }
+ public string description { get; set; }
+ public double pricing { get; set; }
+ public bool IsAvailable { get; set; }
+ }
+}
diff --git a/backend/BackendAssessment/Application/Features/Products/Request/Queries/GetProductRequest.cs b/backend/BackendAssessment/Application/Features/Products/Request/Queries/GetProductRequest.cs
new file mode 100644
index 00000000..ac47a7ff
--- /dev/null
+++ b/backend/BackendAssessment/Application/Features/Products/Request/Queries/GetProductRequest.cs
@@ -0,0 +1,15 @@
+using Application.DTOs.Product;
+using MediatR;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.Features.Products.Request.Queries
+{
+ public class GetProductRequest : IRequest
+ {
+ public Guid Id { get; set; }
+ }
+}
diff --git a/backend/BackendAssessment/Application/Features/Users/Handler/Command/CreateUserCommandHandler.cs b/backend/BackendAssessment/Application/Features/Users/Handler/Command/CreateUserCommandHandler.cs
new file mode 100644
index 00000000..f5984d54
--- /dev/null
+++ b/backend/BackendAssessment/Application/Features/Users/Handler/Command/CreateUserCommandHandler.cs
@@ -0,0 +1,35 @@
+using Application.DTOs.Category;
+using Application.DTOs.User;
+using Application.Features.Users.Request.Command;
+using AutoMapper;
+using Domain.Entites;
+using MediatR;
+using Persistence.Repositories;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.Features.Users.Handler.Command
+{
+ public class CreateUserCommandHandler : IRequestHandler
+ {
+ private readonly IUserRepository _userRepository;
+ private readonly IMapper _mapper;
+
+ public CreateUserCommandHandler(IUserRepository i, IMapper mapper)
+ {
+ _userRepository = i;
+ _mapper = mapper;
+ }
+ public async Task Handle(CreateUserCommand request, CancellationToken cancellationToken)
+ {
+ var user = _mapper.Map(request);
+ var result = await _userRepository.Add(user);
+
+ var response = _mapper.Map(result);
+ return response;
+ }
+ }
+}
diff --git a/backend/BackendAssessment/Application/Features/Users/Handler/Command/UpdateUserCommandHandler.cs b/backend/BackendAssessment/Application/Features/Users/Handler/Command/UpdateUserCommandHandler.cs
new file mode 100644
index 00000000..f7fcaae2
--- /dev/null
+++ b/backend/BackendAssessment/Application/Features/Users/Handler/Command/UpdateUserCommandHandler.cs
@@ -0,0 +1,39 @@
+using Application.DTOs.Category;
+using Application.DTOs.User;
+using Application.Features.Users.Request.Command;
+using AutoMapper;
+using MediatR;
+using Persistence.Repositories;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.Features.Users.Handler.Command
+{
+ internal class UpdateUserCommandHandler : IRequestHandler
+ {
+ private readonly IUserRepository _userRepository;
+ private readonly IMapper _mapper;
+
+ public UpdateUserCommandHandler(IUserRepository i, IMapper mapper)
+ {
+ _userRepository = i;
+ _mapper = mapper;
+ }
+ public async Task Handle(UpdateUserCommand request, CancellationToken cancellationToken)
+ {
+ var category = await _userRepository.Get(request.Id)!;
+ if (category == null)
+ {
+ throw new Exception();
+ }
+
+ var categoryToUpdate = _mapper.Map(request, category);
+ var updatedCategory = await _userRepository.Update(categoryToUpdate);
+ return _mapper.Map(updatedCategory);
+
+ }
+ }
+}
diff --git a/backend/BackendAssessment/Application/Features/Users/Handler/Queries/GetUserRequestHandler.cs b/backend/BackendAssessment/Application/Features/Users/Handler/Queries/GetUserRequestHandler.cs
new file mode 100644
index 00000000..0783957e
--- /dev/null
+++ b/backend/BackendAssessment/Application/Features/Users/Handler/Queries/GetUserRequestHandler.cs
@@ -0,0 +1,37 @@
+using Application.DTOs.Category;
+using Application.DTOs.User;
+using Application.Features.Users.Request.Queries;
+using AutoMapper;
+using MediatR;
+using Persistence.Repositories;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.Features.Users.Handler.Queries
+{
+ public class GetUserRequestHandler : IRequestHandler
+ {
+ private readonly IUserRepository _userRepository;
+ private readonly IMapper _mapper;
+
+
+
+ public GetUserRequestHandler(IUserRepository i, IMapper mapper)
+ {
+ _userRepository = i;
+ _mapper = mapper;
+ }
+ public async Task Handle(GetUserRequest request, CancellationToken cancellationToken)
+ {
+ var user = await _userRepository.Get(request.Id)!;
+ if (user == null)
+ {
+ throw new Exception();
+ }
+ return _mapper.Map(user);
+ }
+ }
+}
diff --git a/backend/BackendAssessment/Application/Features/Users/Request/Command/CreateUserCommand.cs b/backend/BackendAssessment/Application/Features/Users/Request/Command/CreateUserCommand.cs
new file mode 100644
index 00000000..251b4a28
--- /dev/null
+++ b/backend/BackendAssessment/Application/Features/Users/Request/Command/CreateUserCommand.cs
@@ -0,0 +1,19 @@
+using Application.DTOs.User;
+using MediatR;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.Features.Users.Request.Command
+{
+ public class CreateUserCommand : IRequest
+ {
+ public string name { get; set; }
+ public string email { get; set; }
+ public string password { get; set; }
+ public bool isAdmin { get; set; }
+
+ }
+}
diff --git a/backend/BackendAssessment/Application/Features/Users/Request/Command/UpdateUserCommand.cs b/backend/BackendAssessment/Application/Features/Users/Request/Command/UpdateUserCommand.cs
new file mode 100644
index 00000000..a0052305
--- /dev/null
+++ b/backend/BackendAssessment/Application/Features/Users/Request/Command/UpdateUserCommand.cs
@@ -0,0 +1,19 @@
+using Application.DTOs.User;
+using MediatR;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.Features.Users.Request.Command
+{
+ public class UpdateUserCommand : IRequest
+ {
+ public Guid Id { get; set; }
+ public string UserName { get; set; }
+ public string Password { get; set; }
+ public string Email { get; set; }
+
+ }
+}
diff --git a/backend/BackendAssessment/Application/Features/Users/Request/Queries/GetUserRequest.cs b/backend/BackendAssessment/Application/Features/Users/Request/Queries/GetUserRequest.cs
new file mode 100644
index 00000000..e3e14941
--- /dev/null
+++ b/backend/BackendAssessment/Application/Features/Users/Request/Queries/GetUserRequest.cs
@@ -0,0 +1,15 @@
+using Application.DTOs.User;
+using MediatR;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Application.Features.Users.Request.Queries
+{
+ public class GetUserRequest : IRequest
+ {
+ public Guid Id { get; set; }
+ }
+}
diff --git a/backend/BackendAssessment/Application/Profiles/MappingProfile.cs b/backend/BackendAssessment/Application/Profiles/MappingProfile.cs
new file mode 100644
index 00000000..83c2b1c3
--- /dev/null
+++ b/backend/BackendAssessment/Application/Profiles/MappingProfile.cs
@@ -0,0 +1,26 @@
+using AutoMapper;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Application.DTOs.Category;
+using Application.Features.Categories.Request.Command;
+using Application.DTOs.User;
+using Application.Features.Users.Request.Command;
+using Application.Features.Products.Request.Command;
+using Application.DTOs.Product;
+
+namespace Application.Profiles
+{
+ public class MappingProfile : Profile
+ {
+ public MappingProfile()
+ {
+ CreateMap().ReverseMap();
+ CreateMap().ReverseMap();
+ CreateMap().ReverseMap();
+
+ }
+ }
+}
diff --git a/backend/BackendAssessment/Domain/Entites/Category.cs b/backend/BackendAssessment/Domain/Entites/Category.cs
new file mode 100644
index 00000000..add9ec01
--- /dev/null
+++ b/backend/BackendAssessment/Domain/Entites/Category.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Domain.Entites
+{
+ public class Category
+ {
+ public Guid Id { get; set; }
+ public Category()
+ {
+ products = new HashSet();
+ }
+ public string name { get; set; }
+ public string description { get; set; }
+
+ public virtual ICollection products { get; set; }
+ }
+}
diff --git a/backend/BackendAssessment/Domain/Entites/Product.cs b/backend/BackendAssessment/Domain/Entites/Product.cs
new file mode 100644
index 00000000..cedc739e
--- /dev/null
+++ b/backend/BackendAssessment/Domain/Entites/Product.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Domain.Entites
+{
+ public class Product
+ {
+ public Guid Id { get; set; }
+ public string name { get; set; }
+ public string description { get; set; }
+ public double pricing { get; set; }
+ public bool availability { get; set; }
+ public virtual Category category { get; set; }
+ public virtual User user { get; set; }
+ }
+}
diff --git a/backend/BackendAssessment/Domain/Entites/User.cs b/backend/BackendAssessment/Domain/Entites/User.cs
new file mode 100644
index 00000000..435f8618
--- /dev/null
+++ b/backend/BackendAssessment/Domain/Entites/User.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Domain.Entites
+{
+ public class User
+ {
+ public User()
+ {
+ products = new HashSet();
+ }
+ public Guid id { get; set; }
+
+ public string username { get; set; }
+ public string password { get; set; }
+ public string email { get; set; }
+ public bool isAdmin { get; set; }
+
+ public virtual ICollection products { get; set; }
+ }
+}
diff --git a/backend/BackendAssessment/Infrastructure/Infrastructure.csproj b/backend/BackendAssessment/Infrastructure/Infrastructure.csproj
index b62d9762..b85d13b7 100644
--- a/backend/BackendAssessment/Infrastructure/Infrastructure.csproj
+++ b/backend/BackendAssessment/Infrastructure/Infrastructure.csproj
@@ -1,4 +1,4 @@
-
+
net7.0
@@ -8,10 +8,18 @@
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
diff --git a/backend/BackendAssessment/Persistence/Data/ApiDbContext.cs b/backend/BackendAssessment/Persistence/Data/ApiDbContext.cs
new file mode 100644
index 00000000..e5e97506
--- /dev/null
+++ b/backend/BackendAssessment/Persistence/Data/ApiDbContext.cs
@@ -0,0 +1,56 @@
+using Domain.Entites;
+using Microsoft.EntityFrameworkCore;
+
+using Microsoft.Extensions.Hosting;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Persistence.Data
+{
+ public class ApiDbContext : DbContext
+ {
+ public ApiDbContext(DbContextOptions options) : base(options)
+ {
+
+ }
+
+ public DbSet users { get; set; }
+ public DbSet products { get; set; }
+ public DbSet categories { get; set; }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ base.OnModelCreating(modelBuilder);
+
+ modelBuilder.Entity(entity =>
+ {
+ entity.HasMany(p => p.products)
+ .WithOne(u => u.user)
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+ modelBuilder.Entity(entity =>
+ {
+ entity.HasMany(p => p.products)
+ .WithOne(c => c.category)
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+ modelBuilder.Entity(entity =>
+ {
+ entity.HasOne(p => p.user)
+ .WithMany(c => c.products);
+ });
+ modelBuilder.Entity(entity =>
+ {
+ entity.HasOne(c => c.category)
+ .WithMany(p => p.products)
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+
+ }
+
+ }
+}
diff --git a/backend/BackendAssessment/Persistence/Data/ApiDbContextFactory.cs b/backend/BackendAssessment/Persistence/Data/ApiDbContextFactory.cs
new file mode 100644
index 00000000..9357568a
--- /dev/null
+++ b/backend/BackendAssessment/Persistence/Data/ApiDbContextFactory.cs
@@ -0,0 +1,20 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Design;
+using Microsoft.Extensions.Configuration;
+using Persistence.Data;
+
+namespace Persistence
+{
+ public class ApiDBContextFactory : IDesignTimeDbContextFactory
+ {
+ public ApiDbContext CreateDbContext(string[] args)
+ {
+ IConfiguration config = new ConfigurationBuilder().SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), "../WebApi")).AddJsonFile("appsettings.json").Build();
+
+ var connectionString = config.GetConnectionString("DefaultConnection");
+ var builder = new DbContextOptionsBuilder();
+ builder.UseNpgsql(connectionString);
+ return new ApiDbContext(builder.Options);
+ }
+ }
+}
\ No newline at end of file
diff --git a/backend/BackendAssessment/Persistence/DependencyInjection.cs b/backend/BackendAssessment/Persistence/DependencyInjection.cs
new file mode 100644
index 00000000..840b9239
--- /dev/null
+++ b/backend/BackendAssessment/Persistence/DependencyInjection.cs
@@ -0,0 +1,26 @@
+using Persistence.Data;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Persistence.Data;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Persistence
+{
+ public static class DependencyInjection
+ {
+ public static IServiceCollection AddPersistence(this IServiceCollection services, ConfigurationManager configuration)
+ {
+
+ var connectionString = configuration.GetConnectionString("DefaultConnection");
+ services.AddDbContext(opt =>
+ opt.UseNpgsql(connectionString));
+
+ return services;
+ }
+ }
+}
diff --git a/backend/BackendAssessment/Persistence/Migrations/20230905142035_Initial.Designer.cs b/backend/BackendAssessment/Persistence/Migrations/20230905142035_Initial.Designer.cs
new file mode 100644
index 00000000..41039cd2
--- /dev/null
+++ b/backend/BackendAssessment/Persistence/Migrations/20230905142035_Initial.Designer.cs
@@ -0,0 +1,139 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using Persistence.Data;
+
+#nullable disable
+
+namespace Persistence.Migrations
+{
+ [DbContext(typeof(ApiDbContext))]
+ [Migration("20230905142035_Initial")]
+ partial class Initial
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "7.0.10")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Domain.Entites.Category", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("description")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("categories");
+ });
+
+ modelBuilder.Entity("Domain.Entites.Product", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("availability")
+ .HasColumnType("boolean");
+
+ b.Property("categoryId")
+ .HasColumnType("uuid");
+
+ b.Property("description")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("pricing")
+ .HasColumnType("double precision");
+
+ b.Property("userid")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("categoryId");
+
+ b.HasIndex("userid");
+
+ b.ToTable("products");
+ });
+
+ modelBuilder.Entity("Domain.Entites.User", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("email")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("isAdmin")
+ .HasColumnType("boolean");
+
+ b.Property("password")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("username")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("id");
+
+ b.ToTable("users");
+ });
+
+ modelBuilder.Entity("Domain.Entites.Product", b =>
+ {
+ b.HasOne("Domain.Entites.Category", "category")
+ .WithMany("products")
+ .HasForeignKey("categoryId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Domain.Entites.User", "user")
+ .WithMany("products")
+ .HasForeignKey("userid")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("category");
+
+ b.Navigation("user");
+ });
+
+ modelBuilder.Entity("Domain.Entites.Category", b =>
+ {
+ b.Navigation("products");
+ });
+
+ modelBuilder.Entity("Domain.Entites.User", b =>
+ {
+ b.Navigation("products");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/backend/BackendAssessment/Persistence/Migrations/20230905142035_Initial.cs b/backend/BackendAssessment/Persistence/Migrations/20230905142035_Initial.cs
new file mode 100644
index 00000000..98c7dca0
--- /dev/null
+++ b/backend/BackendAssessment/Persistence/Migrations/20230905142035_Initial.cs
@@ -0,0 +1,95 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Persistence.Migrations
+{
+ ///
+ public partial class Initial : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "categories",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ name = table.Column(type: "text", nullable: false),
+ description = table.Column(type: "text", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_categories", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "users",
+ columns: table => new
+ {
+ id = table.Column(type: "uuid", nullable: false),
+ username = table.Column(type: "text", nullable: false),
+ password = table.Column(type: "text", nullable: false),
+ email = table.Column(type: "text", nullable: false),
+ isAdmin = table.Column(type: "boolean", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_users", x => x.id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "products",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ name = table.Column(type: "text", nullable: false),
+ description = table.Column(type: "text", nullable: false),
+ pricing = table.Column(type: "double precision", nullable: false),
+ availability = table.Column(type: "boolean", nullable: false),
+ categoryId = table.Column(type: "uuid", nullable: false),
+ userid = table.Column(type: "uuid", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_products", x => x.Id);
+ table.ForeignKey(
+ name: "FK_products_categories_categoryId",
+ column: x => x.categoryId,
+ principalTable: "categories",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_products_users_userid",
+ column: x => x.userid,
+ principalTable: "users",
+ principalColumn: "id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_products_categoryId",
+ table: "products",
+ column: "categoryId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_products_userid",
+ table: "products",
+ column: "userid");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "products");
+
+ migrationBuilder.DropTable(
+ name: "categories");
+
+ migrationBuilder.DropTable(
+ name: "users");
+ }
+ }
+}
diff --git a/backend/BackendAssessment/Persistence/Migrations/20230905142215_newMigration.Designer.cs b/backend/BackendAssessment/Persistence/Migrations/20230905142215_newMigration.Designer.cs
new file mode 100644
index 00000000..61ea468e
--- /dev/null
+++ b/backend/BackendAssessment/Persistence/Migrations/20230905142215_newMigration.Designer.cs
@@ -0,0 +1,139 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using Persistence.Data;
+
+#nullable disable
+
+namespace Persistence.Migrations
+{
+ [DbContext(typeof(ApiDbContext))]
+ [Migration("20230905142215_newMigration")]
+ partial class newMigration
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "7.0.10")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Domain.Entites.Category", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("description")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("categories");
+ });
+
+ modelBuilder.Entity("Domain.Entites.Product", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("availability")
+ .HasColumnType("boolean");
+
+ b.Property("categoryId")
+ .HasColumnType("uuid");
+
+ b.Property("description")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("pricing")
+ .HasColumnType("double precision");
+
+ b.Property("userid")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("categoryId");
+
+ b.HasIndex("userid");
+
+ b.ToTable("products");
+ });
+
+ modelBuilder.Entity("Domain.Entites.User", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("email")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("isAdmin")
+ .HasColumnType("boolean");
+
+ b.Property("password")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("username")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("id");
+
+ b.ToTable("users");
+ });
+
+ modelBuilder.Entity("Domain.Entites.Product", b =>
+ {
+ b.HasOne("Domain.Entites.Category", "category")
+ .WithMany("products")
+ .HasForeignKey("categoryId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Domain.Entites.User", "user")
+ .WithMany("products")
+ .HasForeignKey("userid")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("category");
+
+ b.Navigation("user");
+ });
+
+ modelBuilder.Entity("Domain.Entites.Category", b =>
+ {
+ b.Navigation("products");
+ });
+
+ modelBuilder.Entity("Domain.Entites.User", b =>
+ {
+ b.Navigation("products");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/backend/BackendAssessment/Persistence/Migrations/20230905142215_newMigration.cs b/backend/BackendAssessment/Persistence/Migrations/20230905142215_newMigration.cs
new file mode 100644
index 00000000..a65aabee
--- /dev/null
+++ b/backend/BackendAssessment/Persistence/Migrations/20230905142215_newMigration.cs
@@ -0,0 +1,22 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Persistence.Migrations
+{
+ ///
+ public partial class newMigration : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+
+ }
+ }
+}
diff --git a/backend/BackendAssessment/Persistence/Migrations/ApiDbContextModelSnapshot.cs b/backend/BackendAssessment/Persistence/Migrations/ApiDbContextModelSnapshot.cs
new file mode 100644
index 00000000..57ce86a6
--- /dev/null
+++ b/backend/BackendAssessment/Persistence/Migrations/ApiDbContextModelSnapshot.cs
@@ -0,0 +1,136 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using Persistence.Data;
+
+#nullable disable
+
+namespace Persistence.Migrations
+{
+ [DbContext(typeof(ApiDbContext))]
+ partial class ApiDbContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "7.0.10")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Domain.Entites.Category", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("description")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("categories");
+ });
+
+ modelBuilder.Entity("Domain.Entites.Product", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("availability")
+ .HasColumnType("boolean");
+
+ b.Property("categoryId")
+ .HasColumnType("uuid");
+
+ b.Property("description")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("pricing")
+ .HasColumnType("double precision");
+
+ b.Property("userid")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("categoryId");
+
+ b.HasIndex("userid");
+
+ b.ToTable("products");
+ });
+
+ modelBuilder.Entity("Domain.Entites.User", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("email")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("isAdmin")
+ .HasColumnType("boolean");
+
+ b.Property("password")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("username")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("id");
+
+ b.ToTable("users");
+ });
+
+ modelBuilder.Entity("Domain.Entites.Product", b =>
+ {
+ b.HasOne("Domain.Entites.Category", "category")
+ .WithMany("products")
+ .HasForeignKey("categoryId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Domain.Entites.User", "user")
+ .WithMany("products")
+ .HasForeignKey("userid")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("category");
+
+ b.Navigation("user");
+ });
+
+ modelBuilder.Entity("Domain.Entites.Category", b =>
+ {
+ b.Navigation("products");
+ });
+
+ modelBuilder.Entity("Domain.Entites.User", b =>
+ {
+ b.Navigation("products");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/backend/BackendAssessment/Persistence/Persistence.csproj b/backend/BackendAssessment/Persistence/Persistence.csproj
index c78c297b..45fd79a7 100644
--- a/backend/BackendAssessment/Persistence/Persistence.csproj
+++ b/backend/BackendAssessment/Persistence/Persistence.csproj
@@ -1,4 +1,4 @@
-
+
net7.0
@@ -8,11 +8,16 @@
-
-
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
+
+
+
+
+
diff --git a/backend/BackendAssessment/Persistence/Repositories/CategoryRepository.cs b/backend/BackendAssessment/Persistence/Repositories/CategoryRepository.cs
new file mode 100644
index 00000000..c065bfac
--- /dev/null
+++ b/backend/BackendAssessment/Persistence/Repositories/CategoryRepository.cs
@@ -0,0 +1,19 @@
+using Application.Persistence.Repositories;
+using Domain.Entites;
+using Persistence.Data;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Persistence.Repositories
+{
+ public class CategoryRepository : GenericRepository
+ {
+ private readonly ApiDbContext _context;
+ public CategoryRepository(ApiDbContext dbContext) : base(dbContext)
+ {
+ }
+ }
+}
diff --git a/backend/BackendAssessment/Persistence/Repositories/GenericRepository.cs b/backend/BackendAssessment/Persistence/Repositories/GenericRepository.cs
new file mode 100644
index 00000000..8da43950
--- /dev/null
+++ b/backend/BackendAssessment/Persistence/Repositories/GenericRepository.cs
@@ -0,0 +1,57 @@
+using Application.Contracts;
+using Microsoft.EntityFrameworkCore;
+using Persistence.Data;
+using Persistence.Repositories;
+
+namespace Application.Persistence.Repositories
+{
+ public class GenericRepository : IGenericRepository where T : class
+ {
+ private readonly ApiDbContext _dbContext;
+
+ public GenericRepository(ApiDbContext dbContext)
+ {
+ _dbContext = dbContext;
+ }
+
+ public async Task Get(Guid id)
+ {
+ return await _dbContext.Set().FindAsync(id);
+ }
+
+ public async Task> GetAll()
+ {
+ return await _dbContext.Set().ToListAsync();
+ }
+
+ public async Task Add(T entity)
+ {
+ await _dbContext.Set().AddAsync(entity);
+ await _dbContext.SaveChangesAsync();
+ return entity;
+ }
+
+ public async Task Update(T entity)
+ {
+ _dbContext.Entry(entity).State = EntityState.Modified;
+ await _dbContext.SaveChangesAsync();
+ return entity;
+ }
+
+ public bool Exists(Guid id)
+ {
+ var entity = Get(id);
+ return entity != null;
+ }
+
+ public void Delete(T entity)
+ {
+ _dbContext.Set().Remove(entity);
+ _dbContext.SaveChanges();
+ }
+
+ }
+
+}
+
+
diff --git a/backend/BackendAssessment/Persistence/Repositories/ProductRepository.cs b/backend/BackendAssessment/Persistence/Repositories/ProductRepository.cs
new file mode 100644
index 00000000..a7dfd304
--- /dev/null
+++ b/backend/BackendAssessment/Persistence/Repositories/ProductRepository.cs
@@ -0,0 +1,24 @@
+using Domain.Entites;
+using Application.Contracts;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Application.Persistence.Repositories;
+using Persistence.Data;
+
+namespace Persistence.Repositories
+{
+ public class ProductRepository : GenericRepository
+ {
+ private readonly ApiDbContext _dbContext;
+ public ProductRepository(ApiDbContext dbContext) : base(dbContext)
+ {
+ _dbContext = dbContext;
+ }
+
+
+ }
+}
diff --git a/backend/BackendAssessment/Persistence/Repositories/UserRepository.cs b/backend/BackendAssessment/Persistence/Repositories/UserRepository.cs
new file mode 100644
index 00000000..d246541e
--- /dev/null
+++ b/backend/BackendAssessment/Persistence/Repositories/UserRepository.cs
@@ -0,0 +1,34 @@
+using Application.Persistence.Repositories;
+using Domain.Entites;
+using Persistence.Data;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Persistence.Repositories
+{
+ public class UserRepository : GenericRepository
+ {
+ private readonly ApiDbContext _dbContext;
+ public UserRepository(ApiDbContext dbContext) : base(dbContext)
+ {
+ _dbContext = dbContext;
+ }
+
+ //public async Task GetByEmail(string email)
+ //{
+ // return await _dbContext.Set()
+ // .Where(u => u.email == email)
+
+ //}
+
+ //public async Task> GetByNameEmail(string email)
+ //{
+ // return await _dbContext.Set()
+ // .Where(u => u.username == email || u.email == email)
+ // .ToListAsync();
+ //}
+ }
+}
diff --git a/backend/BackendAssessment/WebApi/Controllers/CategoryController.cs b/backend/BackendAssessment/WebApi/Controllers/CategoryController.cs
new file mode 100644
index 00000000..a2188e53
--- /dev/null
+++ b/backend/BackendAssessment/WebApi/Controllers/CategoryController.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using System.Xml.Linq;
+using Application.DTOs.Category;
+using Application.Features.Categories.Request.Command;
+using Application.Features.Categories.Request.Queries;
+using Application.Features.Categories.Request.Queries;
+using MediatR;
+using Microsoft.AspNetCore.Mvc;
+
+namespace WebApi.Controllers
+{
+ [ApiController]
+ [Route("api/categories")]
+ public class CategoryController : ControllerBase
+ {
+ private readonly IMediator _mediator;
+
+ public CategoryController(IMediator mediator)
+ {
+ _mediator = mediator;
+ }
+
+ [HttpGet("{categoryId}")]
+ public async Task> GetCategoryById(Guid categoryId)
+ {
+ var query = new GetCategoryRequest { id = categoryId };
+ var category = await _mediator.Send(query);
+
+ if (category == null)
+ {
+ return NotFound();
+ }
+
+ return Ok(category);
+ }
+
+ [HttpPost]
+ public async Task CreateCategory(CategoryRetriveDto createCategoryDTO)
+ {
+ var command = new CreateCategoryCommand { name = createCategoryDTO.name , description = createCategoryDTO.description};
+ await _mediator.Send(command);
+
+ return CreatedAtAction(nameof(GetCategoryById), new { categoryId = createCategoryDTO.Id }, createCategoryDTO);
+ }
+
+ [HttpPut("{categoryId}")]
+ public async Task UpdateCategory(CategoryRetriveDto updateCategoryDTO)
+ {
+
+ var command = new UpdateCategoryCommand {name = updateCategoryDTO.name, description = updateCategoryDTO.description };
+ await _mediator.Send(command);
+
+ return NoContent();
+ }
+
+ }
+}
diff --git a/backend/BackendAssessment/WebApi/Controllers/ProductController.cs b/backend/BackendAssessment/WebApi/Controllers/ProductController.cs
new file mode 100644
index 00000000..2995bcea
--- /dev/null
+++ b/backend/BackendAssessment/WebApi/Controllers/ProductController.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Application.DTOs.Product;
+using Application.Features.Products.Request.Command;
+using Application.Features.Products.Request.Queries;
+using MediatR;
+using Microsoft.AspNetCore.Mvc;
+
+namespace WebApi.Controllers
+{
+ [ApiController]
+ [Route("api/products")]
+ public class ProductController : ControllerBase
+ {
+ private readonly IMediator _mediator;
+
+ public ProductController(IMediator mediator)
+ {
+ _mediator = mediator;
+ }
+
+ [HttpGet("{productId}")]
+ public async Task> GetProductById(Guid productId)
+ {
+ var query = new GetProductRequest { Id = productId };
+ var product = await _mediator.Send(query);
+
+ if (product == null)
+ {
+ return NotFound();
+ }
+
+ return Ok(product);
+ }
+
+ [HttpPost]
+ public async Task CreateProduct(CreateProductDTO createProductDTO)
+ {
+ var command = new CreateProductCommand { name = createProductDTO.name , description=createProductDTO.description,
+ IsAvailable = createProductDTO.isAvailable,pricing = createProductDTO.pricing};
+ await _mediator.Send(command);
+
+ return CreatedAtAction(nameof(GetProductById), new { productId = createProductDTO.Id }, createProductDTO);
+ }
+
+ [HttpPut("{productId}")]
+ public async Task UpdateProduct(CreateProductDTO updateProductDTO)
+ {
+ var command = new UpdateProductCommand {
+ name = updateProductDTO.name,
+ description = updateProductDTO.description,
+ IsAvailable = updateProductDTO.isAvailable,
+ pricing = updateProductDTO.pricing
+ };
+ await _mediator.Send(command);
+
+ return NoContent();
+ }
+ }
+}
+
diff --git a/backend/BackendAssessment/WebApi/Controllers/UserController.cs b/backend/BackendAssessment/WebApi/Controllers/UserController.cs
new file mode 100644
index 00000000..ba7e33a3
--- /dev/null
+++ b/backend/BackendAssessment/WebApi/Controllers/UserController.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Application.DTOs.User;
+using Application.Features.Users.Request.Command;
+using Application.Features.Users.Request.Queries;
+using MediatR;
+using Microsoft.AspNetCore.Mvc;
+
+namespace WebApi.Controllers
+{
+ [ApiController]
+ [Route("api/users")]
+ public class UserController : ControllerBase
+ {
+ private readonly IMediator _mediator;
+
+ public UserController(IMediator mediator)
+ {
+ _mediator = mediator;
+ }
+
+ [HttpGet("{id}")]
+ public async Task> GetUserById(Guid id)
+ {
+ var request = new GetUserRequest { Id = id };
+ var result = await _mediator.Send(request);
+
+ if (result == null)
+ {
+ return NotFound();
+ }
+
+ return Ok(result);
+ }
+
+ [HttpPut("{id}")]
+ public async Task UpdateUser(Guid id, CreateUserDto userDTO)
+ {
+
+ var command = new UpdateUserCommand { UserName = userDTO.username,Password = userDTO.password,Email = userDTO.email };
+ await _mediator.Send(command);
+
+ return NoContent();
+ }
+
+ [HttpPost]
+ public async Task> CreateUser(CreateUserDto UserDTO)
+ {
+ var command = new CreateUserCommand { name = UserDTO.username, password = UserDTO.password, email = UserDTO.email,isAdmin = UserDTO.isAdmin };
+ var result = await _mediator.Send(command);
+
+ return Ok(result);
+ }
+
+ }
+}
+
diff --git a/backend/BackendAssessment/WebApi/Controllers/WeatherForecastController.cs b/backend/BackendAssessment/WebApi/Controllers/WeatherForecastController.cs
deleted file mode 100644
index 7e256fd7..00000000
--- a/backend/BackendAssessment/WebApi/Controllers/WeatherForecastController.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using Microsoft.AspNetCore.Mvc;
-
-namespace WebApi.Controllers;
-
-[ApiController]
-[Route("[controller]")]
-public class WeatherForecastController : ControllerBase
-{
- private static readonly string[] Summaries = new[]
- {
- "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
- };
-
- private readonly ILogger _logger;
-
- public WeatherForecastController(ILogger logger)
- {
- _logger = logger;
- }
-
- [HttpGet(Name = "GetWeatherForecast")]
- public IEnumerable Get()
- {
- return Enumerable.Range(1, 5).Select(index => new WeatherForecast
- {
- Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
- TemperatureC = Random.Shared.Next(-20, 55),
- Summary = Summaries[Random.Shared.Next(Summaries.Length)]
- })
- .ToArray();
- }
-}
\ No newline at end of file
diff --git a/backend/BackendAssessment/WebApi/Program.cs b/backend/BackendAssessment/WebApi/Program.cs
index 8264bac5..a21ba9b0 100644
--- a/backend/BackendAssessment/WebApi/Program.cs
+++ b/backend/BackendAssessment/WebApi/Program.cs
@@ -1,3 +1,4 @@
+using Persistence;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
@@ -6,6 +7,7 @@
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
+builder.Services.AddPersistence(builder.Configuration);
var app = builder.Build();
diff --git a/backend/BackendAssessment/WebApi/WebApi.csproj b/backend/BackendAssessment/WebApi/WebApi.csproj
index 85ed54c3..a206e0a3 100644
--- a/backend/BackendAssessment/WebApi/WebApi.csproj
+++ b/backend/BackendAssessment/WebApi/WebApi.csproj
@@ -8,9 +8,13 @@
-
-
-
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
@@ -19,4 +23,10 @@
+
+
+
+
+
+
diff --git a/backend/BackendAssessment/WebApi/appsettings.json b/backend/BackendAssessment/WebApi/appsettings.json
index 10f68b8c..3b4158ad 100644
--- a/backend/BackendAssessment/WebApi/appsettings.json
+++ b/backend/BackendAssessment/WebApi/appsettings.json
@@ -5,5 +5,9 @@
"Microsoft.AspNetCore": "Warning"
}
},
- "AllowedHosts": "*"
+ "AllowedHosts": "*",
+ "ConnectionStrings": {
+ "DefaultConnection": "Username=postgres;database=ProductHub;Password=aymila777;Host=localhost;Port=5432;Integrated Security=false;Pooling=true;"
+
+ }
}