mirror of
https://github.com/Shchoholiev/shopping-assistant-api.git
synced 2025-04-12 01:48:49 +00:00
Merge pull request #4 from Shchoholiev/feature/SA-51-wishlists-service
Feature/sa 51 wishlists service
This commit is contained in:
commit
6b8b2bdeb3
@ -12,10 +12,12 @@ public static class GraphQlExtention
|
|||||||
.AddQueryType()
|
.AddQueryType()
|
||||||
.AddTypeExtension<UsersQuery>()
|
.AddTypeExtension<UsersQuery>()
|
||||||
.AddTypeExtension<RolesQuery>()
|
.AddTypeExtension<RolesQuery>()
|
||||||
|
.AddTypeExtension<WishlistsQuery>()
|
||||||
.AddMutationType()
|
.AddMutationType()
|
||||||
.AddTypeExtension<AccessMutation>()
|
.AddTypeExtension<AccessMutation>()
|
||||||
.AddTypeExtension<UsersMutation>()
|
.AddTypeExtension<UsersMutation>()
|
||||||
.AddTypeExtension<RolesMutation>()
|
.AddTypeExtension<RolesMutation>()
|
||||||
|
.AddTypeExtension<WishlistsMutation>()
|
||||||
.AddAuthorization()
|
.AddAuthorization()
|
||||||
.InitializeOnStartup(keepWarm: true);
|
.InitializeOnStartup(keepWarm: true);
|
||||||
|
|
||||||
|
17
ShoppingAssistantApi.Api/Mutations/WishlistsMutation.cs
Normal file
17
ShoppingAssistantApi.Api/Mutations/WishlistsMutation.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using ShoppingAssistantApi.Application.IServices;
|
||||||
|
using ShoppingAssistantApi.Application.Models.CreateDtos;
|
||||||
|
using ShoppingAssistantApi.Application.Models.Dtos;
|
||||||
|
|
||||||
|
namespace ShoppingAssistantApi.Api.Mutations;
|
||||||
|
|
||||||
|
[ExtendObjectType(OperationTypeNames.Mutation)]
|
||||||
|
public class WishlistsMutation
|
||||||
|
{
|
||||||
|
public Task<WishlistDto> StartPersonalWishlist(WishlistCreateDto dto, CancellationToken cancellationToken,
|
||||||
|
[Service] IWishlistsService wishlistsService)
|
||||||
|
=> wishlistsService.StartPersonalWishlistAsync(dto, cancellationToken);
|
||||||
|
|
||||||
|
public Task<MessageDto> AddMessageToPersonalWishlist(string wishlistId, MessageCreateDto dto, CancellationToken cancellationToken,
|
||||||
|
[Service] IWishlistsService wishlistsService)
|
||||||
|
=> wishlistsService.AddMessageToPersonalWishlistAsync(wishlistId, dto, cancellationToken);
|
||||||
|
}
|
20
ShoppingAssistantApi.Api/Queries/WishlistsQuery.cs
Normal file
20
ShoppingAssistantApi.Api/Queries/WishlistsQuery.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using HotChocolate.Authorization;
|
||||||
|
using ShoppingAssistantApi.Application.IServices;
|
||||||
|
using ShoppingAssistantApi.Application.Models.Dtos;
|
||||||
|
using ShoppingAssistantApi.Application.Paging;
|
||||||
|
|
||||||
|
namespace ShoppingAssistantApi.Api.Queries;
|
||||||
|
|
||||||
|
[ExtendObjectType(OperationTypeNames.Query)]
|
||||||
|
public class WishlistsQuery
|
||||||
|
{
|
||||||
|
[Authorize]
|
||||||
|
public Task<PagedList<WishlistDto>> GetPersonalWishlistsPageAsync(int pageNumber, int pageSize, CancellationToken cancellationToken,
|
||||||
|
[Service] IWishlistsService wishlistsService)
|
||||||
|
=> wishlistsService.GetPersonalWishlistsPageAsync(pageNumber, pageSize, cancellationToken);
|
||||||
|
|
||||||
|
[Authorize]
|
||||||
|
public Task<WishlistDto> GetPersonalWishlistAsync(string wishlistId, CancellationToken cancellationToken,
|
||||||
|
[Service] IWishlistsService wishlistsService)
|
||||||
|
=> wishlistsService.GetPersonalWishlistAsync(wishlistId, cancellationToken);
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using ShoppingAssistantApi.Domain.Common;
|
||||||
|
|
||||||
|
namespace ShoppingAssistantApi.Application.Exceptions;
|
||||||
|
|
||||||
|
public class UnAuthorizedException<TEntity> : Exception where TEntity : EntityBase
|
||||||
|
{
|
||||||
|
public UnAuthorizedException() { }
|
||||||
|
|
||||||
|
public UnAuthorizedException(ObjectId id) : base(String.Format($"Access to object {id} of type {typeof(TEntity).Name} denied.")) { }
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
using ShoppingAssistantApi.Domain.Entities;
|
||||||
|
|
||||||
|
namespace ShoppingAssistantApi.Application.IRepositories;
|
||||||
|
|
||||||
|
public interface IMessagesRepository : IBaseRepository<Message> { }
|
@ -0,0 +1,9 @@
|
|||||||
|
using System.Linq.Expressions;
|
||||||
|
using ShoppingAssistantApi.Domain.Entities;
|
||||||
|
|
||||||
|
namespace ShoppingAssistantApi.Application.IRepositories;
|
||||||
|
|
||||||
|
public interface IWishlistsRepository : IBaseRepository<Wishlist>
|
||||||
|
{
|
||||||
|
public Task<Wishlist> GetWishlistAsync(Expression<Func<Wishlist, bool>> predicate, CancellationToken cancellationToken);
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
using ShoppingAssistantApi.Application.Models.CreateDtos;
|
||||||
|
using ShoppingAssistantApi.Application.Models.Dtos;
|
||||||
|
using ShoppingAssistantApi.Application.Paging;
|
||||||
|
|
||||||
|
namespace ShoppingAssistantApi.Application.IServices;
|
||||||
|
|
||||||
|
public interface IWishlistsService
|
||||||
|
{
|
||||||
|
Task<WishlistDto> StartPersonalWishlistAsync(WishlistCreateDto dto, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
Task<MessageDto> AddMessageToPersonalWishlistAsync(string wishlistId, MessageCreateDto dto, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
Task<PagedList<WishlistDto>> GetPersonalWishlistsPageAsync(int pageNumber, int pageSize, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
Task<WishlistDto> GetPersonalWishlistAsync(string wishlistId, CancellationToken cancellationToken);
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using ShoppingAssistantApi.Application.Models.CreateDtos;
|
||||||
|
using ShoppingAssistantApi.Application.Models.Dtos;
|
||||||
|
using ShoppingAssistantApi.Domain.Entities;
|
||||||
|
|
||||||
|
namespace ShoppingAssistantApi.Application.MappingProfiles;
|
||||||
|
public class MessageProfile : Profile
|
||||||
|
{
|
||||||
|
public MessageProfile()
|
||||||
|
{
|
||||||
|
CreateMap<Message, MessageDto>().ReverseMap();
|
||||||
|
|
||||||
|
CreateMap<MessageCreateDto, Message>().ReverseMap();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using ShoppingAssistantApi.Application.Models.CreateDtos;
|
||||||
|
using ShoppingAssistantApi.Application.Models.Dtos;
|
||||||
|
using ShoppingAssistantApi.Domain.Entities;
|
||||||
|
|
||||||
|
namespace ShoppingAssistantApi.Application.MappingProfiles;
|
||||||
|
public class WishlistProfile : Profile
|
||||||
|
{
|
||||||
|
public WishlistProfile()
|
||||||
|
{
|
||||||
|
CreateMap<Wishlist, WishlistDto>().ReverseMap();
|
||||||
|
|
||||||
|
CreateMap<WishlistCreateDto, Wishlist>().ReverseMap();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
namespace ShoppingAssistantApi.Application.Models.CreateDtos;
|
||||||
|
|
||||||
|
public class MessageCreateDto
|
||||||
|
{
|
||||||
|
public required string Text { get; set; }
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
namespace ShoppingAssistantApi.Application.Models.CreateDtos;
|
||||||
|
|
||||||
|
public class WishlistCreateDto
|
||||||
|
{
|
||||||
|
public required string Type { get; set; }
|
||||||
|
|
||||||
|
public required string FirstMessageText { get; set; }
|
||||||
|
}
|
12
ShoppingAssistantApi.Application/Models/Dtos/MessageDto.cs
Normal file
12
ShoppingAssistantApi.Application/Models/Dtos/MessageDto.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace ShoppingAssistantApi.Application.Models.Dtos;
|
||||||
|
|
||||||
|
public class MessageDto
|
||||||
|
{
|
||||||
|
public required string Id { get; set; }
|
||||||
|
|
||||||
|
public required string Text { get; set; }
|
||||||
|
|
||||||
|
public required string Role { get; set; }
|
||||||
|
|
||||||
|
public string? CreatedById { get; set; } = null;
|
||||||
|
}
|
12
ShoppingAssistantApi.Application/Models/Dtos/WishlistDto.cs
Normal file
12
ShoppingAssistantApi.Application/Models/Dtos/WishlistDto.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace ShoppingAssistantApi.Application.Models.Dtos;
|
||||||
|
|
||||||
|
public class WishlistDto
|
||||||
|
{
|
||||||
|
public required string Id { get; set; }
|
||||||
|
|
||||||
|
public required string Name { get; set; }
|
||||||
|
|
||||||
|
public required string Type { get; set; }
|
||||||
|
|
||||||
|
public string CreatedById { get; set; } = null!;
|
||||||
|
}
|
13
ShoppingAssistantApi.Domain/Entities/Message.cs
Normal file
13
ShoppingAssistantApi.Domain/Entities/Message.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using ShoppingAssistantApi.Domain.Common;
|
||||||
|
|
||||||
|
namespace ShoppingAssistantApi.Domain.Entities;
|
||||||
|
|
||||||
|
public class Message : EntityBase
|
||||||
|
{
|
||||||
|
public required string Text { get; set; }
|
||||||
|
|
||||||
|
public required string Role { get; set; }
|
||||||
|
|
||||||
|
public ObjectId WishlistId { get; set; }
|
||||||
|
}
|
12
ShoppingAssistantApi.Domain/Entities/Wishlist.cs
Normal file
12
ShoppingAssistantApi.Domain/Entities/Wishlist.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using ShoppingAssistantApi.Domain.Common;
|
||||||
|
|
||||||
|
namespace ShoppingAssistantApi.Domain.Entities;
|
||||||
|
|
||||||
|
public class Wishlist : EntityBase
|
||||||
|
{
|
||||||
|
public required string Name { get; set; }
|
||||||
|
|
||||||
|
public required string Type { get; set; }
|
||||||
|
|
||||||
|
public ICollection<Message>? Messages { get; set; }
|
||||||
|
}
|
7
ShoppingAssistantApi.Domain/Enums/MessageRoles.cs
Normal file
7
ShoppingAssistantApi.Domain/Enums/MessageRoles.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace ShoppingAssistantApi.Domain.Enums;
|
||||||
|
|
||||||
|
public enum MessageRoles
|
||||||
|
{
|
||||||
|
User = 0,
|
||||||
|
Application = 1
|
||||||
|
}
|
7
ShoppingAssistantApi.Domain/Enums/WishlistTypes.cs
Normal file
7
ShoppingAssistantApi.Domain/Enums/WishlistTypes.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace ShoppingAssistantApi.Domain.Enums;
|
||||||
|
|
||||||
|
public enum WishlistTypes
|
||||||
|
{
|
||||||
|
Product = 0,
|
||||||
|
Gift = 1
|
||||||
|
}
|
@ -14,6 +14,7 @@ public static class ServicesExtention
|
|||||||
services.AddScoped<IUserManager, UserManager>();
|
services.AddScoped<IUserManager, UserManager>();
|
||||||
services.AddScoped<ITokensService, TokensService>();
|
services.AddScoped<ITokensService, TokensService>();
|
||||||
services.AddScoped<IUsersService, UsersService>();
|
services.AddScoped<IUsersService, UsersService>();
|
||||||
|
services.AddScoped<IWishlistsService, WishlistsService>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
107
ShoppingAssistantApi.Infrastructure/Services/WishlistsService.cs
Normal file
107
ShoppingAssistantApi.Infrastructure/Services/WishlistsService.cs
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using ShoppingAssistantApi.Application.Exceptions;
|
||||||
|
using ShoppingAssistantApi.Application.GlobalInstances;
|
||||||
|
using ShoppingAssistantApi.Application.IRepositories;
|
||||||
|
using ShoppingAssistantApi.Application.IServices;
|
||||||
|
using ShoppingAssistantApi.Application.Models.CreateDtos;
|
||||||
|
using ShoppingAssistantApi.Application.Models.Dtos;
|
||||||
|
using ShoppingAssistantApi.Application.Paging;
|
||||||
|
using ShoppingAssistantApi.Domain.Entities;
|
||||||
|
using ShoppingAssistantApi.Domain.Enums;
|
||||||
|
|
||||||
|
namespace ShoppingAssistantApi.Infrastructure.Services;
|
||||||
|
|
||||||
|
public class WishlistsService : IWishlistsService
|
||||||
|
{
|
||||||
|
private readonly IWishlistsRepository _wishlistsRepository;
|
||||||
|
|
||||||
|
private readonly IMessagesRepository _messagesRepository;
|
||||||
|
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public WishlistsService(IWishlistsRepository wishlistRepository, IMessagesRepository messageRepository, IMapper mapper)
|
||||||
|
{
|
||||||
|
_wishlistsRepository = wishlistRepository;
|
||||||
|
_messagesRepository = messageRepository;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<WishlistDto> StartPersonalWishlistAsync(WishlistCreateDto dto, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var newWishlist = _mapper.Map<Wishlist>(dto);
|
||||||
|
|
||||||
|
if (!Enum.TryParse<WishlistTypes>(newWishlist.Type, true, out var enumValue) ||
|
||||||
|
!Enum.GetValues<WishlistTypes>().Contains(enumValue))
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("Provided type is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
newWishlist.CreatedById = (ObjectId) GlobalUser.Id;
|
||||||
|
newWishlist.CreatedDateUtc = DateTime.UtcNow;
|
||||||
|
newWishlist.Name = $"{newWishlist.Type} Search";
|
||||||
|
|
||||||
|
var createdWishlist = await _wishlistsRepository.AddAsync(newWishlist, cancellationToken);
|
||||||
|
|
||||||
|
var newMessage = new Message
|
||||||
|
{
|
||||||
|
Text = dto.FirstMessageText,
|
||||||
|
Role = MessageRoles.User.ToString(),
|
||||||
|
WishlistId = createdWishlist.Id
|
||||||
|
};
|
||||||
|
var createdMessage = await _messagesRepository.AddAsync(newMessage, cancellationToken);
|
||||||
|
|
||||||
|
return _mapper.Map<WishlistDto>(createdWishlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<MessageDto> AddMessageToPersonalWishlistAsync(string wishlistId, MessageCreateDto dto, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var newMessage = _mapper.Map<Message>(dto);
|
||||||
|
|
||||||
|
if (!ObjectId.TryParse(wishlistId, out var wishlistObjectId))
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("Provided id is invalid.");
|
||||||
|
}
|
||||||
|
newMessage.WishlistId = wishlistObjectId;
|
||||||
|
newMessage.Role = MessageRoles.User.ToString();
|
||||||
|
newMessage.CreatedById = (ObjectId) GlobalUser.Id;
|
||||||
|
newMessage.CreatedDateUtc = DateTime.UtcNow;
|
||||||
|
|
||||||
|
var relatedWishlist = await _wishlistsRepository.GetWishlistAsync(x => x.Id == wishlistObjectId && x.CreatedById == GlobalUser.Id, cancellationToken);
|
||||||
|
|
||||||
|
if (relatedWishlist == null)
|
||||||
|
{
|
||||||
|
throw new UnAuthorizedException<Wishlist>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var createdMessage = await _messagesRepository.AddAsync(newMessage, cancellationToken);
|
||||||
|
|
||||||
|
return _mapper.Map<MessageDto>(createdMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PagedList<WishlistDto>> GetPersonalWishlistsPageAsync(int pageNumber, int pageSize, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var entities = await _wishlistsRepository.GetPageAsync(pageNumber, pageSize, cancellationToken);
|
||||||
|
var dtos = _mapper.Map<List<WishlistDto>>(entities);
|
||||||
|
var count = await _wishlistsRepository.GetTotalCountAsync();
|
||||||
|
return new PagedList<WishlistDto>(dtos, pageNumber, pageSize, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<WishlistDto> GetPersonalWishlistAsync(string wishlistId, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (!ObjectId.TryParse(wishlistId, out var wishlistObjectId))
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("Provided id is invalid.");
|
||||||
|
}
|
||||||
|
var entity = await _wishlistsRepository.GetWishlistAsync(x => x.Id == wishlistObjectId && x.CreatedById == GlobalUser.Id, cancellationToken);
|
||||||
|
|
||||||
|
Console.WriteLine(" WISHLIST: " + entity.CreatedById + " " + GlobalUser.Id);
|
||||||
|
|
||||||
|
if (entity == null)
|
||||||
|
{
|
||||||
|
throw new UnAuthorizedException<Wishlist>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _mapper.Map<WishlistDto>(entity);
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,15 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using MongoDB.Bson;
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver;
|
||||||
using ShoppingAssistantApi.Application.GlobalInstances;
|
using ShoppingAssistantApi.Application.GlobalInstances;
|
||||||
using ShoppingAssistantApi.Application.IServices;
|
using ShoppingAssistantApi.Application.IServices;
|
||||||
using ShoppingAssistantApi.Application.IServices.Identity;
|
using ShoppingAssistantApi.Application.IServices.Identity;
|
||||||
using ShoppingAssistantApi.Application.Models.CreateDtos;
|
using ShoppingAssistantApi.Application.Models.CreateDtos;
|
||||||
using ShoppingAssistantApi.Application.Models.Dtos;
|
using ShoppingAssistantApi.Application.Models.Dtos;
|
||||||
using ShoppingAssistantApi.Application.Models.Identity;
|
using ShoppingAssistantApi.Application.Models.Identity;
|
||||||
|
using ShoppingAssistantApi.Domain.Entities;
|
||||||
|
using ShoppingAssistantApi.Domain.Enums;
|
||||||
|
using ShoppingAssistantApi.Persistance.Database;
|
||||||
|
|
||||||
namespace ShoppingAssistantApi.Persistance.PersistanceExtentions;
|
namespace ShoppingAssistantApi.Persistance.PersistanceExtentions;
|
||||||
|
|
||||||
@ -19,23 +23,27 @@ public class DbInitialaizer
|
|||||||
|
|
||||||
private readonly ITokensService _tokensService;
|
private readonly ITokensService _tokensService;
|
||||||
|
|
||||||
|
private readonly IMongoCollection<User> _userCollection;
|
||||||
|
|
||||||
|
private readonly IMongoCollection<Wishlist> _wishlistCollection;
|
||||||
|
|
||||||
public IEnumerable<RoleDto> Roles { get; set; }
|
public IEnumerable<RoleDto> Roles { get; set; }
|
||||||
|
|
||||||
public DbInitialaizer(IServiceProvider serviceProvider)
|
public DbInitialaizer(IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
this._usersService = serviceProvider.GetService<IUsersService>();
|
_usersService = serviceProvider.GetService<IUsersService>();
|
||||||
this._rolesService = serviceProvider.GetService<IRolesService>();
|
_rolesService = serviceProvider.GetService<IRolesService>();
|
||||||
this._userManager = serviceProvider.GetService<IUserManager>();
|
_userManager = serviceProvider.GetService<IUserManager>();
|
||||||
this._tokensService = serviceProvider.GetService<ITokensService>();
|
_tokensService = serviceProvider.GetService<ITokensService>();
|
||||||
|
_wishlistCollection = serviceProvider.GetService<MongoDbContext>().Db.GetCollection<Wishlist>("Wishlists");
|
||||||
|
_userCollection = serviceProvider.GetService<MongoDbContext>().Db.GetCollection<User>("Users");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async
|
public async Task InitialaizeDb(CancellationToken cancellationToken)
|
||||||
Task
|
|
||||||
InitialaizeDb(CancellationToken cancellationToken)
|
|
||||||
{
|
{
|
||||||
await this.AddRoles(cancellationToken);
|
await AddRoles(cancellationToken);
|
||||||
await this.AddUsers(cancellationToken);
|
await AddUsers(cancellationToken);
|
||||||
|
await AddWishlistsWithMessages(cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task AddUsers(CancellationToken cancellationToken)
|
public async Task AddUsers(CancellationToken cancellationToken)
|
||||||
@ -73,7 +81,7 @@ InitialaizeDb(CancellationToken cancellationToken)
|
|||||||
_userManager.AccessGuestAsync(guestModel5, cancellationToken)
|
_userManager.AccessGuestAsync(guestModel5, cancellationToken)
|
||||||
);
|
);
|
||||||
|
|
||||||
var guests = await this._usersService.GetUsersPageAsync(1, 4, cancellationToken);
|
var guests = await _usersService.GetUsersPageAsync(1, 4, cancellationToken);
|
||||||
var guestsResult = guests.Items.ToList();
|
var guestsResult = guests.Items.ToList();
|
||||||
|
|
||||||
var user1 = new UserDto
|
var user1 = new UserDto
|
||||||
@ -123,7 +131,7 @@ InitialaizeDb(CancellationToken cancellationToken)
|
|||||||
RefreshToken = _tokensService.GenerateRefreshToken(),
|
RefreshToken = _tokensService.GenerateRefreshToken(),
|
||||||
RefreshTokenExpiryDate = DateTime.Now.AddDays(7),
|
RefreshTokenExpiryDate = DateTime.Now.AddDays(7),
|
||||||
};
|
};
|
||||||
|
|
||||||
GlobalUser.Id = ObjectId.Parse(user1.Id);
|
GlobalUser.Id = ObjectId.Parse(user1.Id);
|
||||||
await _userManager.UpdateAsync(user1, cancellationToken);
|
await _userManager.UpdateAsync(user1, cancellationToken);
|
||||||
|
|
||||||
@ -158,4 +166,51 @@ InitialaizeDb(CancellationToken cancellationToken)
|
|||||||
var dto2 = await _rolesService.AddRoleAsync(role2, cancellationToken);
|
var dto2 = await _rolesService.AddRoleAsync(role2, cancellationToken);
|
||||||
var dto3 = await _rolesService.AddRoleAsync(role3, cancellationToken);
|
var dto3 = await _rolesService.AddRoleAsync(role3, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task AddWishlistsWithMessages(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var user1 = await (await _userCollection.FindAsync(x => x.Email.Equals("shopping.assistant.team@gmail.com"))).FirstAsync();
|
||||||
|
var user2 = await (await _userCollection.FindAsync(x => x.Email.Equals("mykhailo.bilodid@nure.ua"))).FirstAsync();
|
||||||
|
|
||||||
|
var wishlists = new Wishlist[]
|
||||||
|
{
|
||||||
|
new Wishlist
|
||||||
|
{
|
||||||
|
Id = ObjectId.Parse("ab79cde6f69abcd3efab65cd"),
|
||||||
|
Name = "Gaming PC",
|
||||||
|
Type = WishlistTypes.Product.ToString(),
|
||||||
|
CreatedById = user1.Id,
|
||||||
|
Messages = new Message[]
|
||||||
|
{
|
||||||
|
new Message
|
||||||
|
{
|
||||||
|
Text = "Prompt",
|
||||||
|
Role = MessageRoles.User.ToString(),
|
||||||
|
},
|
||||||
|
new Message
|
||||||
|
{
|
||||||
|
Text = "Answer",
|
||||||
|
Role = MessageRoles.Application.ToString(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Wishlist
|
||||||
|
{
|
||||||
|
Id = ObjectId.Parse("ab6c2c2d9edf39abcd1ef9ab"),
|
||||||
|
Name = "Generic Wishlist Name",
|
||||||
|
Type = WishlistTypes.Product.ToString(),
|
||||||
|
CreatedById = user2.Id,
|
||||||
|
Messages = new Message[]
|
||||||
|
{
|
||||||
|
new Message
|
||||||
|
{
|
||||||
|
Text = "Prompt",
|
||||||
|
Role = MessageRoles.User.ToString(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await _wishlistCollection.InsertManyAsync(wishlists);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,8 @@ public static class RepositoriesExtention
|
|||||||
|
|
||||||
services.AddScoped<IRolesRepository, RolesRepository>();
|
services.AddScoped<IRolesRepository, RolesRepository>();
|
||||||
services.AddScoped<IUsersRepository, UsersRepository>();
|
services.AddScoped<IUsersRepository, UsersRepository>();
|
||||||
|
services.AddScoped<IWishlistsRepository, WishlistsRepository>();
|
||||||
|
services.AddScoped<IMessagesRepository, MessagesRepository>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
using ShoppingAssistantApi.Application.IRepositories;
|
||||||
|
using ShoppingAssistantApi.Domain.Entities;
|
||||||
|
using ShoppingAssistantApi.Persistance.Database;
|
||||||
|
|
||||||
|
namespace ShoppingAssistantApi.Persistance.Repositories;
|
||||||
|
|
||||||
|
public class MessagesRepository : BaseRepository<Message>, IMessagesRepository
|
||||||
|
{
|
||||||
|
public MessagesRepository(MongoDbContext db) : base(db, "Messages") { }
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
using System.Linq.Expressions;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
using ShoppingAssistantApi.Application.IRepositories;
|
||||||
|
using ShoppingAssistantApi.Domain.Entities;
|
||||||
|
using ShoppingAssistantApi.Persistance.Database;
|
||||||
|
|
||||||
|
namespace ShoppingAssistantApi.Persistance.Repositories;
|
||||||
|
|
||||||
|
public class WishlistsRepository : BaseRepository<Wishlist>, IWishlistsRepository
|
||||||
|
{
|
||||||
|
public WishlistsRepository(MongoDbContext db) : base(db, "Wishlists") { }
|
||||||
|
|
||||||
|
public async Task<Wishlist> GetWishlistAsync(Expression<Func<Wishlist, bool>> predicate, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return await (await _collection.FindAsync(predicate)).FirstOrDefaultAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
281
ShoppingAssistantApi.Tests/Tests/WishlistsTests.cs
Normal file
281
ShoppingAssistantApi.Tests/Tests/WishlistsTests.cs
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
using ShoppingAssistantApi.Tests.TestExtentions;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using Xunit;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using ShoppingAssistantApi.Domain.Enums;
|
||||||
|
|
||||||
|
namespace ShoppingAssistantApi.Tests.Tests;
|
||||||
|
|
||||||
|
[Collection("Tests")]
|
||||||
|
public class WishlistsTests : IClassFixture<TestingFactory<Program>>
|
||||||
|
{
|
||||||
|
private readonly HttpClient _httpClient;
|
||||||
|
|
||||||
|
private const string WISHLIST_TESTING_USER_EMAIL = "shopping.assistant.team@gmail.com";
|
||||||
|
|
||||||
|
private const string WISHLIST_TESTING_USER_PASSWORD = "Yuiop12345";
|
||||||
|
|
||||||
|
private const string TESTING_WISHLIST_ID = "ab79cde6f69abcd3efab65cd";
|
||||||
|
|
||||||
|
public WishlistsTests(TestingFactory<Program> factory)
|
||||||
|
{
|
||||||
|
_httpClient = factory.CreateClient();
|
||||||
|
factory.InitialaizeData().GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task StartPersonalWishlistAsync_ValidWishlistModel_ReturnsNewWishlistModels()
|
||||||
|
{
|
||||||
|
var tokensModel = await AccessExtention.Login(WISHLIST_TESTING_USER_EMAIL, WISHLIST_TESTING_USER_PASSWORD, _httpClient);
|
||||||
|
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokensModel.AccessToken);
|
||||||
|
var user = await UserExtention.GetCurrentUser(_httpClient);
|
||||||
|
|
||||||
|
var mutation = new
|
||||||
|
{
|
||||||
|
query = "mutation startPersonalWishlist($dto: WishlistCreateDtoInput!) { startPersonalWishlist (dto: $dto) { id, name, type, createdById } }",
|
||||||
|
variables = new
|
||||||
|
{
|
||||||
|
dto = new
|
||||||
|
{
|
||||||
|
firstMessageText = "First message",
|
||||||
|
type = WishlistTypes.Product.ToString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var jsonPayload = JsonConvert.SerializeObject(mutation);
|
||||||
|
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
using var response = await _httpClient.PostAsync("graphql", content);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
|
||||||
|
var responseString = await response.Content.ReadAsStringAsync();
|
||||||
|
var document = JsonConvert.DeserializeObject<dynamic>(responseString);
|
||||||
|
|
||||||
|
var wishlistId = (string) document.data.startPersonalWishlist.id;
|
||||||
|
var wishlistCreatedById = (string) document.data.startPersonalWishlist.createdById;
|
||||||
|
var wishlistType = (string) document.data.startPersonalWishlist.type;
|
||||||
|
var wishlistName = (string) document.data.startPersonalWishlist.name;
|
||||||
|
|
||||||
|
Assert.Equal(user.Id, wishlistCreatedById);
|
||||||
|
Assert.Equal(WishlistTypes.Product.ToString(), wishlistType);
|
||||||
|
Assert.Equal($"{WishlistTypes.Product} Search", wishlistName);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetPersonalWishlistsPage_ValidPageNumberAndSize_ReturnsPage()
|
||||||
|
{
|
||||||
|
var tokensModel = await AccessExtention.Login(WISHLIST_TESTING_USER_EMAIL, WISHLIST_TESTING_USER_PASSWORD, _httpClient);
|
||||||
|
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokensModel.AccessToken);
|
||||||
|
var user = await UserExtention.GetCurrentUser(_httpClient);
|
||||||
|
|
||||||
|
var query = new
|
||||||
|
{
|
||||||
|
query = "query personalWishlistsPage($pageNumber: Int!, $pageSize: Int!) { personalWishlistsPage(pageNumber: $pageNumber, pageSize: $pageSize) { items { createdById, id, name, type } } }",
|
||||||
|
variables = new
|
||||||
|
{
|
||||||
|
pageNumber = 1,
|
||||||
|
pageSize = 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var jsonPayload = JsonConvert.SerializeObject(query);
|
||||||
|
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
using var response = await _httpClient.PostAsync("graphql", content);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
|
||||||
|
var responseString = await response.Content.ReadAsStringAsync();
|
||||||
|
var document = JsonConvert.DeserializeObject<dynamic>(responseString);
|
||||||
|
|
||||||
|
var personalWishlistsPageItems = Enumerable.ToList(document.data.personalWishlistsPage.items);
|
||||||
|
var personalWishlistCreatedById = (string) personalWishlistsPageItems[0].createdById;
|
||||||
|
|
||||||
|
Assert.NotEmpty(personalWishlistsPageItems);
|
||||||
|
Assert.Equal(user.Id, personalWishlistCreatedById);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetPersonalWishlist_ValidWishlistIdOrAuthorizedAccess_ReturnsWishlistDto()
|
||||||
|
{
|
||||||
|
var tokensModel = await AccessExtention.Login(WISHLIST_TESTING_USER_EMAIL, WISHLIST_TESTING_USER_PASSWORD, _httpClient);
|
||||||
|
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokensModel.AccessToken);
|
||||||
|
var user = await UserExtention.GetCurrentUser(_httpClient);
|
||||||
|
|
||||||
|
var query = new
|
||||||
|
{
|
||||||
|
query = "query personalWishlist($wishlistId: String!) { personalWishlist(wishlistId: $wishlistId) { createdById, id, name, type } }",
|
||||||
|
variables = new
|
||||||
|
{
|
||||||
|
wishlistId = TESTING_WISHLIST_ID
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var jsonPayload = JsonConvert.SerializeObject(query);
|
||||||
|
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
using var response = await _httpClient.PostAsync("graphql", content);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
|
||||||
|
var responseString = await response.Content.ReadAsStringAsync();
|
||||||
|
var document = JsonConvert.DeserializeObject<dynamic>(responseString);
|
||||||
|
|
||||||
|
var personalWishlistId = (string) document.data.personalWishlist.id;
|
||||||
|
var personalWishlistName = (string) document.data.personalWishlist.name;
|
||||||
|
var personalWishlistType = (string) document.data.personalWishlist.type;
|
||||||
|
var personalWishlistCreatedById = (string) document.data.personalWishlist.createdById;
|
||||||
|
|
||||||
|
Assert.Equal(TESTING_WISHLIST_ID, personalWishlistId);
|
||||||
|
Assert.Equal("Gaming PC", personalWishlistName);
|
||||||
|
Assert.Equal(WishlistTypes.Product.ToString(), personalWishlistType);
|
||||||
|
Assert.Equal(user.Id, personalWishlistCreatedById);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AddMessageToPersonalWishlist_ValidMessageModel_ReturnsNewMessageModel()
|
||||||
|
{
|
||||||
|
var tokensModel = await AccessExtention.Login(WISHLIST_TESTING_USER_EMAIL, WISHLIST_TESTING_USER_PASSWORD, _httpClient);
|
||||||
|
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokensModel.AccessToken);
|
||||||
|
var user = await UserExtention.GetCurrentUser(_httpClient);
|
||||||
|
|
||||||
|
const string MESSAGE_TEXT = "Second Message";
|
||||||
|
|
||||||
|
var mutation = new
|
||||||
|
{
|
||||||
|
query = "mutation addMessageToPersonalWishlist($wishlistId: String!, $dto: MessageCreateDtoInput!) { addMessageToPersonalWishlist (wishlistId: $wishlistId, dto: $dto) { role, text, createdById } }",
|
||||||
|
variables = new
|
||||||
|
{
|
||||||
|
wishlistId = TESTING_WISHLIST_ID,
|
||||||
|
dto = new
|
||||||
|
{
|
||||||
|
text = MESSAGE_TEXT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var jsonPayload = JsonConvert.SerializeObject(mutation);
|
||||||
|
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
using var response = await _httpClient.PostAsync("graphql", content);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
|
||||||
|
var responseString = await response.Content.ReadAsStringAsync();
|
||||||
|
var document = JsonConvert.DeserializeObject<dynamic>(responseString);
|
||||||
|
|
||||||
|
var messageRole = (string) document.data.addMessageToPersonalWishlist.role;
|
||||||
|
var messageText = (string) document.data.addMessageToPersonalWishlist.text;
|
||||||
|
var messageCreatedById = (string) document.data.addMessageToPersonalWishlist.createdById;
|
||||||
|
|
||||||
|
Assert.Equal(MessageRoles.User.ToString(), messageRole);
|
||||||
|
Assert.Equal(MESSAGE_TEXT, messageText);
|
||||||
|
Assert.Equal(user.Id, messageCreatedById);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task StartPersonalWishlistAsync_InvalidWishlistModel_ReturnsInternalServerError()
|
||||||
|
{
|
||||||
|
var tokensModel = await AccessExtention.Login(WISHLIST_TESTING_USER_EMAIL, WISHLIST_TESTING_USER_PASSWORD, _httpClient);
|
||||||
|
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokensModel.AccessToken);
|
||||||
|
var user = await UserExtention.GetCurrentUser(_httpClient);
|
||||||
|
|
||||||
|
var mutation = new
|
||||||
|
{
|
||||||
|
query = "mutation startPersonalWishlist($dto: WishlistCreateDtoInput!) { startPersonalWishlist (dto: $dto) { id, name, type, createdById } }",
|
||||||
|
variables = new
|
||||||
|
{
|
||||||
|
dto = new
|
||||||
|
{
|
||||||
|
firstMessageText = "First message",
|
||||||
|
type = "Invalid type" // Invalid Wishlist Type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var jsonPayload = JsonConvert.SerializeObject(mutation);
|
||||||
|
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
using var response = await _httpClient.PostAsync("graphql", content);
|
||||||
|
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetPersonalWishlist_InvalidWishlistId_ReturnsInternalServerError()
|
||||||
|
{
|
||||||
|
var tokensModel = await AccessExtention.Login(WISHLIST_TESTING_USER_EMAIL, WISHLIST_TESTING_USER_PASSWORD, _httpClient);
|
||||||
|
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokensModel.AccessToken);
|
||||||
|
var user = await UserExtention.GetCurrentUser(_httpClient);
|
||||||
|
|
||||||
|
var query = new
|
||||||
|
{
|
||||||
|
query = "query personalWishlist($wishlistId: String!) { personalWishlist(wishlistId: $wishlistId) { createdById, id, name, type } }",
|
||||||
|
variables = new
|
||||||
|
{
|
||||||
|
wishlistId = "1234567890abcdef12345678" // Invalid wishlistId
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var jsonPayload = JsonConvert.SerializeObject(query);
|
||||||
|
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
using var response = await _httpClient.PostAsync("graphql", content);
|
||||||
|
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetPersonalWishlist_UnAuthorizedAccess_ReturnsInternalServerError()
|
||||||
|
{
|
||||||
|
var tokensModel = await AccessExtention.Login(WISHLIST_TESTING_USER_EMAIL, WISHLIST_TESTING_USER_PASSWORD, _httpClient);
|
||||||
|
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokensModel.AccessToken);
|
||||||
|
var user = await UserExtention.GetCurrentUser(_httpClient);
|
||||||
|
|
||||||
|
var query = new
|
||||||
|
{
|
||||||
|
query = "query personalWishlist($wishlistId: String!) { personalWishlist(wishlistId: $wishlistId) { createdById, id, name, type } }",
|
||||||
|
variables = new
|
||||||
|
{
|
||||||
|
wishlistId = "ab6c2c2d9edf39abcd1ef9ab" // Other user's wishlist
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var jsonPayload = JsonConvert.SerializeObject(query);
|
||||||
|
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
using var response = await _httpClient.PostAsync("graphql", content);
|
||||||
|
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AddMessageToPersonalWishlist_InvalidMessageModel_ReturnsInternalServerError()
|
||||||
|
{
|
||||||
|
var tokensModel = await AccessExtention.Login(WISHLIST_TESTING_USER_EMAIL, WISHLIST_TESTING_USER_PASSWORD, _httpClient);
|
||||||
|
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokensModel.AccessToken);
|
||||||
|
var user = await UserExtention.GetCurrentUser(_httpClient);
|
||||||
|
|
||||||
|
const string MESSAGE_TEXT = "Second Message";
|
||||||
|
|
||||||
|
var mutation = new
|
||||||
|
{
|
||||||
|
query = "mutation addMessageToPersonalWishlist($wishlistId: String!, $dto: MessageCreateDtoInput!) { addMessageToPersonalWishlist (wishlistId: $wishlistId, dto: $dto) { role, text, createdById } }",
|
||||||
|
variables = new
|
||||||
|
{
|
||||||
|
wishlistId = "8125jad7g12", // Invalid wishlistId
|
||||||
|
dto = new
|
||||||
|
{
|
||||||
|
text = MESSAGE_TEXT,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var jsonPayload = JsonConvert.SerializeObject(mutation);
|
||||||
|
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
using var response = await _httpClient.PostAsync("graphql", content);
|
||||||
|
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user