diff --git a/ShoppingAssistantApi.Infrastructure/Services/Identity/UserManager.cs b/ShoppingAssistantApi.Infrastructure/Services/Identity/UserManager.cs index 7720477..22cba2c 100644 --- a/ShoppingAssistantApi.Infrastructure/Services/Identity/UserManager.cs +++ b/ShoppingAssistantApi.Infrastructure/Services/Identity/UserManager.cs @@ -116,7 +116,7 @@ public class UserManager : ServiceBase, IUserManager .GetOneAsync(r => r.Token == tokensModel.RefreshToken && r.CreatedById == userId - && r.IsDeleted == false, cancellationToken); + , cancellationToken); if (refreshTokenModel == null || refreshTokenModel.ExpiryDateUTC < DateTime.UtcNow) { throw new SecurityTokenExpiredException(); @@ -310,7 +310,7 @@ public class UserManager : ServiceBase, IUserManager private async Task CheckAndUpgradeToUserAsync(User user, CancellationToken cancellationToken) { - if (user.Roles.Any(x => x.Name == "Guest") && !user.Roles.Any(x => x.Name == "User")) + if (user.Roles.Any(x => x.Name == "Guest" && x.IsDeleted == false) && !user.Roles.Any(x => x.Name == "User" && x.IsDeleted == false)) { if (!string.IsNullOrEmpty(user.PasswordHash) && (!string.IsNullOrEmpty(user.Email) || !string.IsNullOrEmpty(user.Phone))) { diff --git a/ShoppingAssistantApi.Infrastructure/Services/ProductService.cs b/ShoppingAssistantApi.Infrastructure/Services/ProductService.cs index a67809a..c6ca80d 100644 --- a/ShoppingAssistantApi.Infrastructure/Services/ProductService.cs +++ b/ShoppingAssistantApi.Infrastructure/Services/ProductService.cs @@ -42,7 +42,7 @@ public class ProductService : IProductService "\n[Products] - return semicolon separated product names"; var countOfMessage = await _messagesRepository - .GetCountAsync(message=>message.WishlistId==ObjectId.Parse((wishlistId)), cancellationToken); + .GetCountAsync(message=>message.WishlistId == ObjectId.Parse((wishlistId)), cancellationToken); var previousMessages = await _wishlistsService .GetMessagesPageFromPersonalWishlistAsync(wishlistId, 1, countOfMessage, cancellationToken); diff --git a/ShoppingAssistantApi.Infrastructure/Services/WishlistsService.cs b/ShoppingAssistantApi.Infrastructure/Services/WishlistsService.cs index 42ae372..ddc2ec5 100644 --- a/ShoppingAssistantApi.Infrastructure/Services/WishlistsService.cs +++ b/ShoppingAssistantApi.Infrastructure/Services/WishlistsService.cs @@ -73,7 +73,8 @@ public class WishlistsService : IWishlistsService var wishlist = await TryGetPersonalWishlist(wishlistObjectId, cancellationToken); - var firstUserMessage = (await _messagesRepository.GetPageAsync(1, 1, x => x.WishlistId == wishlistObjectId && x.Role == MessageRoles.User.ToString(), cancellationToken)).First(); + var firstUserMessage = + (await _messagesRepository.GetPageAsync(1, 1, x => x.WishlistId == wishlistObjectId && x.Role == MessageRoles.User.ToString(), cancellationToken)).First(); var chatCompletionRequest = new ChatCompletionRequest { diff --git a/ShoppingAssistantApi.Persistance/Repositories/BaseRepository.cs b/ShoppingAssistantApi.Persistance/Repositories/BaseRepository.cs index 8a128ff..1087ee9 100644 --- a/ShoppingAssistantApi.Persistance/Repositories/BaseRepository.cs +++ b/ShoppingAssistantApi.Persistance/Repositories/BaseRepository.cs @@ -3,6 +3,7 @@ using MongoDB.Driver; using ShoppingAssistantApi.Application.IRepositories; using ShoppingAssistantApi.Domain.Common; using ShoppingAssistantApi.Persistance.Database; +using System; using System.Linq.Expressions; namespace ShoppingAssistantApi.Persistance.Repositories; @@ -21,12 +22,13 @@ public abstract class BaseRepository : IBaseRepository where T public async Task GetOneAsync(ObjectId id, CancellationToken cancellationToken) { - return await this._collection.Find(x => x.Id == id).FirstOrDefaultAsync(cancellationToken); + return await this._collection.Find(x => x.Id == id && x.IsDeleted == false).FirstOrDefaultAsync(cancellationToken); } public async Task GetOneAsync(Expression> predicate, CancellationToken cancellationToken) { - return await this._collection.Find(predicate).FirstOrDefaultAsync(cancellationToken); + return await this._collection.Find(Builders.Filter.Where(predicate) & Builders.Filter.Where(x => !x.IsDeleted)) + .FirstOrDefaultAsync(cancellationToken); } public async Task AddAsync(TEntity entity, CancellationToken cancellationToken) @@ -37,7 +39,7 @@ public abstract class BaseRepository : IBaseRepository where T public async Task> GetPageAsync(int pageNumber, int pageSize, CancellationToken cancellationToken) { - return await this._collection.Find(Builders.Filter.Empty) + return await this._collection.Find(Builders.Filter.Where(x => !x.IsDeleted)) .Skip((pageNumber - 1) * pageSize) .Limit(pageSize) .ToListAsync(cancellationToken); @@ -45,7 +47,7 @@ public abstract class BaseRepository : IBaseRepository where T public async Task> GetPageAsync(int pageNumber, int pageSize, Expression> predicate, CancellationToken cancellationToken) { - return await this._collection.Find(predicate) + return await this._collection.Find(Builders.Filter.Where(predicate) & Builders.Filter.Where(x => !x.IsDeleted)) .Skip((pageNumber - 1) * pageSize) .Limit(pageSize) .ToListAsync(cancellationToken); @@ -53,17 +55,18 @@ public abstract class BaseRepository : IBaseRepository where T public async Task GetTotalCountAsync() { - return (int)(await this._collection.EstimatedDocumentCountAsync()); + var filter = Builders.Filter.Eq("IsDeleted", false); + return (int)(await this._collection.CountDocumentsAsync(x => !x.IsDeleted)); } public async Task GetCountAsync(Expression> predicate, CancellationToken cancellationToken) { - return (int)(await this._collection.CountDocumentsAsync(predicate, cancellationToken: cancellationToken)); + return (int)(await this._collection.CountDocumentsAsync(Builders.Filter.Where(predicate) & Builders.Filter.Where(x => !x.IsDeleted), cancellationToken: cancellationToken)); } public async Task ExistsAsync(Expression> predicate, CancellationToken cancellationToken) { - return await this._collection.Find(predicate).AnyAsync(cancellationToken); + return await this._collection.Find(Builders.Filter.Where(predicate) & Builders.Filter.Where(x => !x.IsDeleted)).AnyAsync(cancellationToken); } public async Task DeleteAsync(TEntity entity, CancellationToken cancellationToken) diff --git a/ShoppingAssistantApi.Persistance/Repositories/MessagesRepository.cs b/ShoppingAssistantApi.Persistance/Repositories/MessagesRepository.cs index 55734c9..1c6368e 100644 --- a/ShoppingAssistantApi.Persistance/Repositories/MessagesRepository.cs +++ b/ShoppingAssistantApi.Persistance/Repositories/MessagesRepository.cs @@ -12,7 +12,7 @@ public class MessagesRepository : BaseRepository, IMessagesRepository public async Task> GetPageStartingFromEndAsync(int pageNumber, int pageSize, Expression> predicate, CancellationToken cancellationToken) { - return await _collection.Find(predicate) + return await _collection.Find(Builders.Filter.Where(predicate) & Builders.Filter.Where(x => !x.IsDeleted)) .SortByDescending(x => x.CreatedDateUtc) .Skip((pageNumber - 1) * pageSize) .Limit(pageSize) diff --git a/ShoppingAssistantApi.Persistance/Repositories/RolesRepository.cs b/ShoppingAssistantApi.Persistance/Repositories/RolesRepository.cs index 2c09d63..480a368 100644 --- a/ShoppingAssistantApi.Persistance/Repositories/RolesRepository.cs +++ b/ShoppingAssistantApi.Persistance/Repositories/RolesRepository.cs @@ -13,11 +13,11 @@ public class RolesRepository : BaseRepository, IRolesRepository public async Task GetRoleAsync(ObjectId id, CancellationToken cancellationToken) { - return await (await this._collection.FindAsync(x => x.Id == id)).FirstOrDefaultAsync(cancellationToken); + return await (await this._collection.FindAsync(x => x.Id == id && x.IsDeleted == false)).FirstOrDefaultAsync(cancellationToken); } public async Task GetRoleAsync(Expression> predicate, CancellationToken cancellationToken) { - return await (await this._collection.FindAsync(predicate)).FirstOrDefaultAsync(cancellationToken); + return await (await this._collection.FindAsync(Builders.Filter.Where(predicate) & Builders.Filter.Where(x => !x.IsDeleted))).FirstOrDefaultAsync(cancellationToken); } } \ No newline at end of file diff --git a/ShoppingAssistantApi.Persistance/Repositories/UsersRepository.cs b/ShoppingAssistantApi.Persistance/Repositories/UsersRepository.cs index 39b4ab5..459cccd 100644 --- a/ShoppingAssistantApi.Persistance/Repositories/UsersRepository.cs +++ b/ShoppingAssistantApi.Persistance/Repositories/UsersRepository.cs @@ -14,12 +14,12 @@ public class UsersRepository : BaseRepository, IUsersRepository public async Task GetUserAsync(ObjectId id, CancellationToken cancellationToken) { - return await (await this._collection.FindAsync(x => x.Id == id)).FirstOrDefaultAsync(cancellationToken); + return await (await this._collection.FindAsync(x => x.Id == id && x.IsDeleted == false)).FirstOrDefaultAsync(cancellationToken); } public async Task GetUserAsync(Expression> predicate, CancellationToken cancellationToken) { - return await (await this._collection.FindAsync(predicate)).FirstOrDefaultAsync(cancellationToken); + return await (await this._collection.FindAsync(Builders.Filter.Where(predicate) & Builders.Filter.Where(x => !x.IsDeleted))).FirstOrDefaultAsync(cancellationToken); } public async Task UpdateUserAsync(User user, CancellationToken cancellationToken) @@ -39,6 +39,6 @@ public class UsersRepository : BaseRepository, IUsersRepository }; return await this._collection.FindOneAndUpdateAsync( - Builders.Filter.Eq(u => u.Id, user.Id), updateDefinition, options, cancellationToken); + Builders.Filter.Eq(u => u.Id, user.Id) & Builders.Filter.Where(x => !x.IsDeleted), updateDefinition, options, cancellationToken); } } diff --git a/ShoppingAssistantApi.Persistance/Repositories/WishlistsRepository.cs b/ShoppingAssistantApi.Persistance/Repositories/WishlistsRepository.cs index d015cf8..ec760ba 100644 --- a/ShoppingAssistantApi.Persistance/Repositories/WishlistsRepository.cs +++ b/ShoppingAssistantApi.Persistance/Repositories/WishlistsRepository.cs @@ -13,13 +13,13 @@ public class WishlistsRepository : BaseRepository, IWishlistsRepositor public async Task GetWishlistAsync(Expression> predicate, CancellationToken cancellationToken) { - return await (await _collection.FindAsync(predicate)).FirstOrDefaultAsync(cancellationToken); + return await (await _collection.FindAsync(Builders.Filter.Where(predicate) & Builders.Filter.Where(x => !x.IsDeleted))).FirstOrDefaultAsync(cancellationToken); } public async Task UpdateWishlistNameAsync(ObjectId wishlistId, string newName, ObjectId updatedById, CancellationToken cancellationToken) { - var filterDefinition = Builders.Filter.Eq(w => w.Id, wishlistId); + var filterDefinition = Builders.Filter.Eq(w => w.Id, wishlistId) & Builders.Filter.Where(x => !x.IsDeleted); var updateDefinition = Builders.Update .Set(w => w.Name, newName) diff --git a/ShoppingAssistantApi.Tests/TestExtentions/DbInitializer.cs b/ShoppingAssistantApi.Tests/TestExtentions/DbInitializer.cs index f4346d7..360aa2b 100644 --- a/ShoppingAssistantApi.Tests/TestExtentions/DbInitializer.cs +++ b/ShoppingAssistantApi.Tests/TestExtentions/DbInitializer.cs @@ -109,6 +109,7 @@ public class DbInitializer var wishlistId2 = ObjectId.Parse("ab6c2c2d9edf39abcd1ef9ab"); var wishlistId3 = ObjectId.Parse("ab7c8c2d9edf39abcd1ef9ab"); var wishlistId4 = ObjectId.Parse("ab8c8c2d9edf39abcd1ef9ab"); + var wishlistId5 = ObjectId.Parse("65575253dbe88a3c118e1ca2"); var wishlists = new Wishlist[] { @@ -121,6 +122,14 @@ public class DbInitializer CreatedDateUtc = DateTime.UtcNow }, new Wishlist + { + Id = wishlistId5, + Name = "Gaming PC", + Type = WishlistTypes.Product.ToString(), + CreatedById = user1.Id, + CreatedDateUtc = DateTime.UtcNow + }, + new Wishlist { Id = wishlistId2, Name = "Generic Wishlist Name", @@ -162,6 +171,8 @@ public class DbInitializer var wishlistId2 = ObjectId.Parse("ab6c2c2d9edf39abcd1ef9ab"); var wishlistId3 = ObjectId.Parse("ab7c8c2d9edf39abcd1ef9ab"); var wishlistId4 = ObjectId.Parse("ab8c8c2d9edf39abcd1ef9ab"); + var wishlistId5 = ObjectId.Parse("65575253dbe88a3c118e1ca2"); + var messages = new Message[] { @@ -211,6 +222,51 @@ public class DbInitializer CreatedDateUtc = DateTime.UtcNow.AddSeconds(50) }, new Message + { + Text = "Message 1", + Role = MessageRoles.User.ToString(), + WishlistId = wishlistId5, + CreatedById = user1.Id, + CreatedDateUtc = DateTime.UtcNow + }, + new Message + { + Text = "Message 2", + Role = MessageRoles.Application.ToString(), + WishlistId = wishlistId5, + CreatedDateUtc = DateTime.UtcNow.AddSeconds(5) + }, + new Message + { + Text = "Message 3", + Role = MessageRoles.User.ToString(), + WishlistId = wishlistId5, + CreatedById = user1.Id, + CreatedDateUtc = DateTime.UtcNow.AddSeconds(20) + }, + new Message + { + Text = "Message 4", + Role = MessageRoles.Application.ToString(), + WishlistId = wishlistId5, + CreatedDateUtc = DateTime.UtcNow.AddSeconds(25) + }, + new Message + { + Text = "Message 5", + Role = MessageRoles.User.ToString(), + WishlistId = wishlistId5, + CreatedById = user1.Id, + CreatedDateUtc = DateTime.UtcNow.AddSeconds(45) + }, + new Message + { + Text = "Message 6", + Role = MessageRoles.Application.ToString(), + WishlistId = wishlistId5, + CreatedDateUtc = DateTime.UtcNow.AddSeconds(50) + }, + new Message { Text = "Prompt", Role = MessageRoles.User.ToString(), @@ -249,6 +305,7 @@ public class DbInitializer var wishlistId1 = ObjectId.Parse("ab79cde6f69abcd3efab65cd"); var wishlistId2 = ObjectId.Parse("ab6c2c2d9edf39abcd1ef9ab"); + var wishlistId3 = ObjectId.Parse("65575253dbe88a3c118e1ca2"); var products = new Product[] { @@ -285,6 +342,40 @@ public class DbInitializer WishlistId = wishlistId1, CreatedById = user1.Id, CreatedDateUtc = DateTime.UtcNow + }, + new Product + { + Name = "AMD Ryzen 5 5600G 6-Core 12-Thread Unlocked Desktop Processor with Radeon Graphics", + Description = "Features best-in-class graphics performance in a desktop processor for smooth 1080p gaming, no graphics card required", + Rating = 4.8, + Price = 120, + Url = "https://a.co/d/5ceuIrq", + ImagesUrls = new string[] + { + "https://m.media-amazon.com/images/I/51f2hkWjTlL._AC_SL1200_.jpg", + "https://m.media-amazon.com/images/I/51iji7Gel-L._AC_SL1200_.jpg" + }, + WasOpened = false, + WishlistId = wishlistId3, + CreatedById = user1.Id, + CreatedDateUtc = DateTime.UtcNow + }, + new Product + { + Name = "Samsung 970 EVO Plus SSD 2TB NVMe M.2 Internal Solid State Hard Drive, V-NAND Technology, Storage and Memory Expansion for Gaming, Graphics w/ Heat Control, Max Speed, MZ-V7S2T0B/AM ", + Description = "7 Year Limited Warranty: The 970 EVO Plus provides up to 1200 TBW (Terabytes Written) with 5-years of protection for exceptional endurance powered by the latest V-NAND technology and Samsung's reputation for quality ", + Rating = 4.8, + Price = 153, + Url = "https://a.co/d/gxnuqs1", + ImagesUrls = new string[] + { + "https://m.media-amazon.com/images/I/51Brl+iYtvL._AC_SL1001_.jpg", + "https://m.media-amazon.com/images/I/51GOfLlVwoL._AC_SL1001_.jpg" + }, + WasOpened = false, + WishlistId = wishlistId3, + CreatedById = user1.Id, + CreatedDateUtc = DateTime.UtcNow }, }; diff --git a/ShoppingAssistantApi.Tests/Tests/WishlistsTests.cs b/ShoppingAssistantApi.Tests/Tests/WishlistsTests.cs index 4d1e5d8..3ed5336 100644 --- a/ShoppingAssistantApi.Tests/Tests/WishlistsTests.cs +++ b/ShoppingAssistantApi.Tests/Tests/WishlistsTests.cs @@ -26,6 +26,7 @@ public class WishlistsTests : TestsBase private const string TestingValidWishlistId = "ab79cde6f69abcd3efab65cd"; + private const string TestingValidWishlistId2 = "65575253dbe88a3c118e1ca2"; public WishlistsTests(TestingFactory factory) : base(factory) @@ -178,7 +179,7 @@ public class WishlistsTests : TestsBase }", variables = new { - wishlistId = TestingValidWishlistId + wishlistId = TestingValidWishlistId2 } }; @@ -246,7 +247,7 @@ public class WishlistsTests : TestsBase }", variables = new { - wishlistId = TestingValidWishlistId, + wishlistId = TestingValidWishlistId2, pageNumber = 1, pageSize = 2 } @@ -823,7 +824,7 @@ public class WishlistsTests : TestsBase }", variables = new { - wishlistId = TestingValidWishlistId, + wishlistId = TestingValidWishlistId2, pageNumber = 100, pageSize = 2 } @@ -878,7 +879,7 @@ public class WishlistsTests : TestsBase query = "query productsPageFromPersonalWishlist($wishlistId: String!, $pageNumber: Int!, $pageSize: Int!) { productsPageFromPersonalWishlist (wishlistId: $wishlistId, pageNumber: $pageNumber, pageSize: $pageSize) { hasNextPage, hasPreviousPage, items { id, url, name, description, rating, imagesUrls, wasOpened, wishlistId }, pageNumber, pageSize, totalItems, totalPages } }", variables = new { - wishlistId = TestingValidWishlistId, + wishlistId = TestingValidWishlistId2, pageNumber = 1, pageSize = 100 } @@ -890,7 +891,7 @@ public class WishlistsTests : TestsBase Assert.NotNull(pagedList); Assert.Equal("Samsung 970 EVO Plus SSD 2TB NVMe M.2 Internal Solid State Hard Drive, V-NAND Technology, Storage and Memory Expansion for Gaming, Graphics w/ Heat Control, Max Speed, MZ-V7S2T0B/AM ", pagedList.Items.ToList()[1].Name); - Assert.Equal(TestingValidWishlistId, pagedList.Items.ToList()[1].WishlistId); + Assert.Equal(TestingValidWishlistId2, pagedList.Items.ToList()[1].WishlistId); } [Fact]