diff --git a/Data/Product.json b/Data/Product.json index aa29c29..a2b28c4 100644 --- a/Data/Product.json +++ b/Data/Product.json @@ -13,15 +13,15 @@ "Lowest": { "ProductSourceId": "60b9ceed-b34c-45ad-a142-af0ec5491d91", "Status": 1, - "Price": 15.90, - "FoundDate": "2022-01-12T16:38:23.5065248+01:00" + "Price": 15.9, + "FoundDate": "2022-01-17T22:11:38.0596893+01:00" }, "Recent": [ { "ProductSourceId": "60b9ceed-b34c-45ad-a142-af0ec5491d91", "Status": 1, - "Price": 15.90, - "FoundDate": "2022-01-12T16:38:23.5065248+01:00" + "Price": 15.9, + "FoundDate": "2022-01-17T22:11:38.0596893+01:00" } ], "Id": "6a52bd42-d19e-4572-9295-28e01e7e7417" @@ -46,20 +46,20 @@ "ProductSourceId": "ebeaa98d-aedb-4bb8-b539-1de7e1ee25cc", "Status": 1, "Price": 699, - "FoundDate": "2022-01-12T11:47:19.3724935+01:00" + "FoundDate": "2022-01-17T22:11:30.3167162+01:00" }, "Recent": [ { "ProductSourceId": "4753f887-5b20-41de-a06b-3c159262a273", "Status": 1, "Price": 749, - "FoundDate": "2022-01-12T11:47:19.3724893+01:00" + "FoundDate": "2022-01-17T22:11:30.3167121+01:00" }, { "ProductSourceId": "ebeaa98d-aedb-4bb8-b539-1de7e1ee25cc", "Status": 1, "Price": 699, - "FoundDate": "2022-01-12T11:47:19.3724935+01:00" + "FoundDate": "2022-01-17T22:11:30.3167162+01:00" } ], "Id": "5486193d-b417-4936-b71c-be250317dc81" @@ -88,27 +88,27 @@ "Lowest": { "ProductSourceId": "d786a796-b93c-468b-8fda-a2892d72802a", "Status": 1, - "Price": 139.99, - "FoundDate": "2022-01-12T16:39:00.6305374+01:00" + "Price": 149, + "FoundDate": "2022-01-17T22:15:35.0988116+01:00" }, "Recent": [ + { + "ProductSourceId": "3b27b7fc-369d-4f90-ba4c-f209c1a0153b", + "Status": 1, + "Price": 179, + "FoundDate": "2022-01-17T22:15:35.0988087+01:00" + }, { "ProductSourceId": "d786a796-b93c-468b-8fda-a2892d72802a", "Status": 1, - "Price": 139.99, - "FoundDate": "2022-01-12T16:39:00.6305374+01:00" + "Price": 149, + "FoundDate": "2022-01-17T22:15:35.0988116+01:00" }, { "ProductSourceId": "1778e5f5-b73d-418b-b3b8-06412828f54f", "Status": 3, "Price": null, - "FoundDate": "2022-01-12T16:39:00.6305405+01:00" - }, - { - "ProductSourceId": "3b27b7fc-369d-4f90-ba4c-f209c1a0153b", - "Status": 1, - "Price": 179, - "FoundDate": "2022-01-12T16:39:00.6305407+01:00" + "FoundDate": "2022-01-17T22:15:35.0988117+01:00" } ], "Id": "e10533c4-8e07-443c-b751-52020da1e7ee" @@ -132,21 +132,21 @@ "Lowest": { "ProductSourceId": "923b83ed-3fcb-43ca-80b0-0e9e717ec9c6", "Status": 1, - "Price": 519.80, - "FoundDate": "2022-01-12T16:40:36.1338264+01:00" + "Price": 519.8, + "FoundDate": "2022-01-17T22:15:31.6599739+01:00" }, "Recent": [ { "ProductSourceId": "5f5a72a4-d6ad-4cab-9fb9-9d5839fa2a03", "Status": 3, "Price": null, - "FoundDate": "2022-01-12T16:40:36.1338221+01:00" + "FoundDate": "2022-01-17T22:15:31.6599714+01:00" }, { "ProductSourceId": "923b83ed-3fcb-43ca-80b0-0e9e717ec9c6", "Status": 1, - "Price": 519.80, - "FoundDate": "2022-01-12T16:40:36.1338264+01:00" + "Price": 519.8, + "FoundDate": "2022-01-17T22:15:31.6599739+01:00" } ], "Id": "1b60bf08-2d90-4f85-99ce-3d26d19bb696" @@ -173,13 +173,13 @@ "ProductSourceId": "cbb43572-35b9-4408-9e52-09f934b97336", "Status": 3, "Price": null, - "FoundDate": "2022-01-12T16:41:33.6760236+01:00" + "FoundDate": "2022-01-17T22:14:25.9009655+01:00" }, { "ProductSourceId": "ab80a6f9-c175-4c10-8f69-aee23e7efc64", "Status": 3, "Price": null, - "FoundDate": "2022-01-12T16:41:33.6760279+01:00" + "FoundDate": "2022-01-17T22:14:25.9009746+01:00" } ], "Id": "fa6bca3a-0e5b-4efd-acc0-b20fc07fd269" @@ -204,20 +204,20 @@ "ProductSourceId": "b129f9f2-416b-493e-af3c-ff0f255a66e9", "Status": 1, "Price": 499.99, - "FoundDate": "2022-01-12T16:41:36.2769149+01:00" + "FoundDate": "2022-01-17T22:14:24.1309443+01:00" }, "Recent": [ - { - "ProductSourceId": "b129f9f2-416b-493e-af3c-ff0f255a66e9", - "Status": 1, - "Price": 499.99, - "FoundDate": "2022-01-12T16:41:36.2769149+01:00" - }, { "ProductSourceId": "aa039437-a86f-4cf7-9283-90c63a95e142", "Status": 3, "Price": null, - "FoundDate": "2022-01-12T16:41:36.2769184+01:00" + "FoundDate": "2022-01-17T22:14:24.1309405+01:00" + }, + { + "ProductSourceId": "b129f9f2-416b-493e-af3c-ff0f255a66e9", + "Status": 1, + "Price": 499.99, + "FoundDate": "2022-01-17T22:14:24.1309443+01:00" } ], "Id": "76ed6168-fbae-4fb3-a572-bc70c4d1e567" @@ -236,15 +236,15 @@ "Lowest": { "ProductSourceId": "831217bc-0784-4d57-a6a5-d71bf6b2bd19", "Status": 1, - "Price": 367.64, - "FoundDate": "2022-01-12T11:47:18.4194776+01:00" + "Price": 360.94, + "FoundDate": "2022-01-17T22:11:58.4706763+01:00" }, "Recent": [ { "ProductSourceId": "831217bc-0784-4d57-a6a5-d71bf6b2bd19", "Status": 1, - "Price": 367.64, - "FoundDate": "2022-01-12T11:47:18.4194776+01:00" + "Price": 360.94, + "FoundDate": "2022-01-17T22:11:58.4706763+01:00" } ], "Id": "40467c0b-d5ff-45d6-b1b7-30d8ab344dc8" @@ -492,14 +492,14 @@ "ProductSourceId": "281a09b0-4e6e-4b30-a016-92d02a459303", "Status": 1, "Price": 499, - "FoundDate": "2022-01-12T11:47:12.1233434+01:00" + "FoundDate": "2022-01-17T22:11:27.5942189+01:00" }, "Recent": [ { "ProductSourceId": "281a09b0-4e6e-4b30-a016-92d02a459303", "Status": 1, "Price": 499, - "FoundDate": "2022-01-12T11:47:12.1233434+01:00" + "FoundDate": "2022-01-17T22:11:27.5942189+01:00" } ], "Id": "115d3cd7-ce8e-4058-ab7c-451d23385607" @@ -519,14 +519,14 @@ "ProductSourceId": "ebac9915-2f1f-4dc2-affa-d6d16eeb9fbc", "Status": 1, "Price": 79.99, - "FoundDate": "2022-01-12T16:38:47.9170131+01:00" + "FoundDate": "2022-01-17T22:11:34.1555861+01:00" }, "Recent": [ { "ProductSourceId": "ebac9915-2f1f-4dc2-affa-d6d16eeb9fbc", "Status": 1, "Price": 79.99, - "FoundDate": "2022-01-12T16:38:47.9170131+01:00" + "FoundDate": "2022-01-17T22:11:34.1555861+01:00" } ], "Id": "3ce265ce-4edc-49d1-ace5-7733ba8430ee" @@ -650,19 +650,24 @@ "AgentArgument": "B082WD5YV9" } ], - "Lowest": null, + "Lowest": { + "ProductSourceId": "f1c56af5-3385-4337-991d-c39bbcc4e529", + "Status": 1, + "Price": 339.99, + "FoundDate": "2022-01-17T22:15:29.2184901+01:00" + }, "Recent": [ { "ProductSourceId": "511e7ef2-ba34-444d-b8d5-35ab3ccb7e67", "Status": 3, "Price": null, - "FoundDate": "2022-01-12T16:40:45.8696497+01:00" + "FoundDate": "2022-01-17T22:15:29.2184846+01:00" }, { "ProductSourceId": "f1c56af5-3385-4337-991d-c39bbcc4e529", - "Status": 3, - "Price": null, - "FoundDate": "2022-01-12T16:40:45.8696535+01:00" + "Status": 1, + "Price": 339.99, + "FoundDate": "2022-01-17T22:15:29.2184901+01:00" } ], "Id": "b2392eeb-f7d2-4bca-b8ce-e1b9ee9698d8" diff --git a/Directory.Build.targets b/Directory.Build.targets index e6a0ab2..1581b76 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -14,10 +14,10 @@ - - - - + + + + diff --git a/PriceChecker.Core.Tests/CommandHandlers/AgentsStoreWithOverwriteCommandHandlerTests.cs b/PriceChecker.Core.Tests/CommandHandlers/AgentsStoreWithOverwriteCommandHandlerTests.cs index e2c74f5..b484e4a 100644 --- a/PriceChecker.Core.Tests/CommandHandlers/AgentsStoreWithOverwriteCommandHandlerTests.cs +++ b/PriceChecker.Core.Tests/CommandHandlers/AgentsStoreWithOverwriteCommandHandlerTests.cs @@ -34,7 +34,7 @@ public async Task Process__Agents_are_overwritten_and_event_published() await _sut.ProcessAsync(command); // Verify - _agentRepoMock.Verify(x => x.Overwrite(It.IsAny()), Times.Once); + _agentRepoMock.Verify(x => x.OverwriteAsync(It.IsAny()), Times.Once); _eventBusMock.Verify(x => x.Publish(It.IsAny()), Times.Once); } @@ -59,9 +59,9 @@ public async Task Process__Products_agent_keys_are_refined() products[1].Id // renaming and removing }; Agent[] agentsUpdated = Array.Empty(); - _agentRepoMock.Setup(x => x.Overwrite(It.IsAny())) + _agentRepoMock.Setup(x => x.OverwriteAsync(It.IsAny())) .Callback(x => agentsUpdated = x); - _agentQueryMock.Setup(x => x.GetAllAsync()).ReturnsAsync(agentsUpdated); + _agentQueryMock.Setup(x => x.GetAllAsync()).ReturnsAsync(() => agentsUpdated); // Pre-Assert Assert.Equal(agents[1].Key, products[0].Sources[1].AgentKey); @@ -72,12 +72,12 @@ public async Task Process__Products_agent_keys_are_refined() await _sut.ProcessAsync(command); // Verify - _productRepoMock.Verify(x => x.Overwrite(It.Is(y => + _productRepoMock.Verify(x => x.OverwriteAsync(It.Is(y => y[0].Sources[1].AgentKey.Equals(agentsToUpdate[1].Key) && y[1].Sources[1].AgentKey.Equals(agentsToUpdate[4].Key) && y[1].Sources.Length == 2 )), Times.Once); - _eventBusMock.Verify(x => x.Publish(It.Is(y => - y.Entities.SequenceEqual(affectedProductIds))), Times.Once); + _eventBusMock.Verify(x => x.Publish(It.Is(y => + y.Updated.Keys.SequenceEqual(affectedProductIds))), Times.Once); } } diff --git a/PriceChecker.Core.Tests/Repositories/AgentRepositoryTests.cs b/PriceChecker.Core.Tests/Repositories/AgentRepositoryTests.cs index 4ef17c1..47c0fec 100644 --- a/PriceChecker.Core.Tests/Repositories/AgentRepositoryTests.cs +++ b/PriceChecker.Core.Tests/Repositories/AgentRepositoryTests.cs @@ -49,7 +49,7 @@ public async Task Delete__Removes_appripriate_agent() var agentToDelete = _agents[1]; // Act - _sut.Delete(agentToDelete.Id); + await _sut.DeleteAsync(agentToDelete.Id); // Verify Assert.Null(await _sut.FindByIdAsync(agentToDelete.Id)); @@ -63,7 +63,7 @@ public async Task Delete__When_no_agent_found__Breaks_operation() var agentCount = agents.Count(); // Act - _sut.Delete(Guid.NewGuid()); + await _sut.DeleteAsync(Guid.NewGuid()); // Verify Assert.Equal(agentCount, (await _sut.GetAllAsync()).Count()); @@ -77,13 +77,13 @@ public async Task Store__Replaces_all_existing_agents_and_updates_cache_and_fire var previousAgents = (await _sut.GetAllAsync()).ToArray(); // Act - _sut.Overwrite(newAgents); + await _sut.OverwriteAsync(newAgents); // Verify Assert.False((await _sut.GetAllAsync()).Except(newAgents).Any()); _persisterMock.Verify(x => x.Store(It.IsAny(), It.Is((List p) => p.SequenceEqual(newAgents)))); - _eventBusMock.Verify(x => x.Publish(It.Is(e => e.Entities.Count == newAgents.Length)), Times.Once); - _eventBusMock.Verify(x => x.Publish(It.Is(e => e.Entities.Count == previousAgents.Length)), Times.Once); + _eventBusMock.Verify(x => x.Publish(It.Is(e => e.Added.Count == newAgents.Length + && e.Deleted.Count == previousAgents.Length)), Times.Once); } } diff --git a/PriceChecker.Core.Tests/Repositories/ProductRepositoryTests.cs b/PriceChecker.Core.Tests/Repositories/ProductRepositoryTests.cs index 91f3194..a7d0b67 100644 --- a/PriceChecker.Core.Tests/Repositories/ProductRepositoryTests.cs +++ b/PriceChecker.Core.Tests/Repositories/ProductRepositoryTests.cs @@ -23,7 +23,7 @@ public ProductRepositoryTests() _agents = ModelHelpers.SampleManyAgents(_products).ToArray(); foreach (var agent in _agents) - _agentQueryMock.Setup(x => x.FindByKey(agent.Key)).Returns(agent); + _agentQueryMock.Setup(x => x.FindByKeyAsync(agent.Key)).ReturnsAsync(agent); _persisterMock.Setup(x => x.LoadCollection(It.IsAny())) .Returns(_products); @@ -59,13 +59,13 @@ public async Task FindById__Returns_appropriate_product() } [Fact] - public async Task Delete__Removes_appripriate_product() + public async Task Delete__Removes_appropriate_product() { // Arrange var productToDelete = _products[1]; // Act - _sut.Delete(productToDelete.Id); + await _sut.DeleteAsync(productToDelete.Id); // Verify Assert.Null(await _sut.FindByIdAsync(productToDelete.Id)); @@ -78,25 +78,25 @@ public async Task Delete__When_no_product_found__Breaks_operation() var productCount = (await _sut.GetAllAsync()).Count(); // Act - _sut.Delete(Guid.NewGuid()); + await _sut.DeleteAsync(Guid.NewGuid()); // Verify Assert.Equal(productCount, (await _sut.GetAllAsync()).Count()); } [Fact] - public void Store__For_existing_product__Saves_it_and_fires_event() + public async Task Store__For_existing_product__Saves_it_and_fires_event() { // Arrange var product = _products[1]; // Act - _sut.Store(product); + await _sut.StoreAsync(product); // Verify _persisterMock.Verify(x => x.Store(It.IsAny(), It.Is((List p) => p.SequenceEqual(_products)))); - _eventBusMock.Verify(x => x.Publish(It.Is(e => e.Entities.First() == product.Id)), Times.Once); + _eventBusMock.Verify(x => x.Publish(It.Is(e => e.Updated.First().Key == product.Id)), Times.Once); } [Fact] @@ -107,13 +107,13 @@ public async Task Store__For_nonexisting_product__Adds_it_and_fires_event() var productCount = (await _sut.GetAllAsync()).Count(); // Act - _sut.Store(product); + await _sut.StoreAsync(product); // Verify var expectedProducts = _products.Concat(new [] { product }); _persisterMock.Verify(x => x.Store(It.IsAny(), It.Is((List p) => p.SequenceEqual(expectedProducts)))); - _eventBusMock.Verify(x => x.Publish(It.Is(e => e.Entities.First() == product.Id)), Times.Once); + _eventBusMock.Verify(x => x.Publish(It.Is(e => e.Added.First().Key == product.Id)), Times.Once); Assert.Equal(productCount + 1, (await _sut.GetAllAsync()).Count()); } @@ -126,7 +126,7 @@ public async Task Store__When_id_is_empty__Adds_product_with_autogenerated_id() var productCount = (await _sut.GetAllAsync()).Count(); // Act - _sut.Store(product); + await _sut.StoreAsync(product); // Verify Assert.NotEqual(Guid.Empty, product.Id); diff --git a/PriceChecker.Core/CommandHandlers/AgentDeleteCommandHandler.cs b/PriceChecker.Core/CommandHandlers/AgentDeleteCommandHandler.cs index 0ac499b..54d2046 100644 --- a/PriceChecker.Core/CommandHandlers/AgentDeleteCommandHandler.cs +++ b/PriceChecker.Core/CommandHandlers/AgentDeleteCommandHandler.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using Genius.Atom.Infrastructure.Commands; using Genius.Atom.Infrastructure.Events; using Genius.PriceChecker.Core.Commands; @@ -18,12 +17,10 @@ public AgentDeleteCommandHandler(IAgentRepository agentRepo, IEventBus eventBus) _eventBus = eventBus; } - public Task ProcessAsync(AgentDeleteCommand command) + public async Task ProcessAsync(AgentDeleteCommand command) { - _agentRepo.Delete(command.AgentId); + await _agentRepo.DeleteAsync(command.AgentId); _eventBus.Publish(new AgentsAffectedEvent()); - - return Task.CompletedTask; } } diff --git a/PriceChecker.Core/CommandHandlers/AgentsStoreWithOverwriteCommandHandler.cs b/PriceChecker.Core/CommandHandlers/AgentsStoreWithOverwriteCommandHandler.cs index 7747f61..bc4edc8 100644 --- a/PriceChecker.Core/CommandHandlers/AgentsStoreWithOverwriteCommandHandler.cs +++ b/PriceChecker.Core/CommandHandlers/AgentsStoreWithOverwriteCommandHandler.cs @@ -1,9 +1,9 @@ -using System.Threading.Tasks; using Genius.Atom.Infrastructure.Commands; using Genius.Atom.Infrastructure.Entities; using Genius.Atom.Infrastructure.Events; using Genius.PriceChecker.Core.Commands; using Genius.PriceChecker.Core.Messages; +using Genius.PriceChecker.Core.Models; using Genius.PriceChecker.Core.Repositories; namespace Genius.PriceChecker.Core.CommandHandlers; @@ -29,7 +29,7 @@ public AgentsStoreWithOverwriteCommandHandler(IAgentRepository agentRepo, public async Task ProcessAsync(AgentsStoreWithOverwriteCommand command) { - _agentRepo.Overwrite(command.Agents); + await _agentRepo.OverwriteAsync(command.Agents); _eventBus.Publish(new AgentsAffectedEvent()); await RefineProductSources(); @@ -67,7 +67,7 @@ private async Task RefineProductSources() if (!affectedProductsIds.Any()) return; - _productRepo.Overwrite(products); - _eventBus.Publish(new EntitiesUpdatedEvent(affectedProductsIds)); + await _productRepo.OverwriteAsync(products); + _eventBus.Publish(new EntitiesAffectedEvent(typeof(Product), EntityAffectedEventType.Updated, affectedProductsIds.ToArray())); } } diff --git a/PriceChecker.Core/CommandHandlers/ProductCreateOrUpdateCommandHandler.cs b/PriceChecker.Core/CommandHandlers/ProductCreateOrUpdateCommandHandler.cs index c099b2c..4e35817 100644 --- a/PriceChecker.Core/CommandHandlers/ProductCreateOrUpdateCommandHandler.cs +++ b/PriceChecker.Core/CommandHandlers/ProductCreateOrUpdateCommandHandler.cs @@ -24,15 +24,15 @@ public ProductCreateOrUpdateCommandHandler(IProductRepository productRepo, IProd _eventBus = eventBus; } - public Task ProcessAsync(ProductCreateCommand command) + public async Task ProcessAsync(ProductCreateCommand command) { var product = new Product(); UpdateProperties(product, command); - _productRepo.Store(product); + await _productRepo.StoreAsync(product); _eventBus.Publish(new ProductsAffectedEvent()); - return Task.FromResult(product.Id); + return product.Id; } public async Task ProcessAsync(ProductUpdateCommand command) @@ -41,7 +41,7 @@ public async Task ProcessAsync(ProductUpdateCommand command) Guard.NotNull(product); UpdateProperties(product, command); - _productRepo.Store(product); + await _productRepo.StoreAsync(product); _eventBus.Publish(new ProductsAffectedEvent()); } diff --git a/PriceChecker.Core/CommandHandlers/ProductDeleteCommandHandler.cs b/PriceChecker.Core/CommandHandlers/ProductDeleteCommandHandler.cs index b9994d4..5f6a4ca 100644 --- a/PriceChecker.Core/CommandHandlers/ProductDeleteCommandHandler.cs +++ b/PriceChecker.Core/CommandHandlers/ProductDeleteCommandHandler.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using Genius.Atom.Infrastructure.Commands; using Genius.Atom.Infrastructure.Events; using Genius.PriceChecker.Core.Commands; @@ -18,12 +17,10 @@ public ProductDeleteCommandHandler(IProductRepository productRepo, IEventBus eve _eventBus = eventBus; } - public Task ProcessAsync(ProductDeleteCommand command) + public async Task ProcessAsync(ProductDeleteCommand command) { - _productRepo.Delete(command.ProductId); + await _productRepo.DeleteAsync(command.ProductId); _eventBus.Publish(new ProductsAffectedEvent()); - - return Task.CompletedTask; } } diff --git a/PriceChecker.Core/CommandHandlers/ProductDropPricesCommandHandler.cs b/PriceChecker.Core/CommandHandlers/ProductDropPricesCommandHandler.cs index c86e96c..5d73852 100644 --- a/PriceChecker.Core/CommandHandlers/ProductDropPricesCommandHandler.cs +++ b/PriceChecker.Core/CommandHandlers/ProductDropPricesCommandHandler.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using Genius.Atom.Infrastructure.Commands; using Genius.PriceChecker.Core.Commands; using Genius.PriceChecker.Core.Models; @@ -25,6 +24,6 @@ public async Task ProcessAsync(ProductDropPricesCommand command) product.Lowest = null; product.Recent = Array.Empty(); - _productRepo.Store(product); + await _productRepo.StoreAsync(product); } } diff --git a/PriceChecker.Core/Models/Agent.cs b/PriceChecker.Core/Models/Agent.cs index 28965df..cb1ddb3 100644 --- a/PriceChecker.Core/Models/Agent.cs +++ b/PriceChecker.Core/Models/Agent.cs @@ -14,6 +14,7 @@ public object Clone() { return new Agent() { + Id = Id, Key = Key, Url = Url, PricePattern = PricePattern, diff --git a/PriceChecker.Core/Repositories/AgentRepository.cs b/PriceChecker.Core/Repositories/AgentRepository.cs index 04a5cac..f8d707e 100644 --- a/PriceChecker.Core/Repositories/AgentRepository.cs +++ b/PriceChecker.Core/Repositories/AgentRepository.cs @@ -8,7 +8,7 @@ namespace Genius.PriceChecker.Core.Repositories; public interface IAgentQueryService : IQueryService { - Agent? FindByKey(string agentKey); + Task FindByKeyAsync(string agentKey); } public interface IAgentRepository : IRepository @@ -22,22 +22,18 @@ public AgentRepository(IEventBus eventBus, IJsonPersister persister, ILogger FindByIdAsync(Guid entityId) - { - return Task.FromResult(base.FindById(entityId)); - } + public new Task FindByIdAsync(Guid entityId) + => base.FindByIdAsync(entityId); - public Agent? FindByKey(string agentKey) + public async Task FindByKeyAsync(string agentKey) { - return GetAll().FirstOrDefault(x => x.Key == agentKey); + return (await GetAllAsync()).FirstOrDefault(x => x.Key == agentKey); } - public Task> GetAllAsync() - { - return Task.FromResult(base.GetAll()); - } + public new Task> GetAllAsync() + => base.GetAllAsync(); - protected override void FillUpRelations(Agent entity) + protected override Task FillUpRelationsAsync(Agent entity) { // Backwards compatibility if (string.IsNullOrEmpty(entity.Handler)) @@ -45,6 +41,6 @@ protected override void FillUpRelations(Agent entity) entity.Handler = nameof(AgentHandlers.SimpleRegex); } - base.FillUpRelations(entity); + return Task.CompletedTask; } } diff --git a/PriceChecker.Core/Repositories/ProductRepository.cs b/PriceChecker.Core/Repositories/ProductRepository.cs index 26e17b2..e0ac31f 100644 --- a/PriceChecker.Core/Repositories/ProductRepository.cs +++ b/PriceChecker.Core/Repositories/ProductRepository.cs @@ -26,24 +26,20 @@ public ProductRepository(IEventBus eventBus, IJsonPersister persister, _agentRepo = agentQuery; } - public Task FindByIdAsync(Guid entityId) - { - return Task.FromResult(base.FindById(entityId)); - } + public new Task FindByIdAsync(Guid entityId) + => base.FindByIdAsync(entityId); - public Task> GetAllAsync() - { - return Task.FromResult(base.GetAll()); - } + public new Task> GetAllAsync() + => base.GetAllAsync(); - protected override void FillUpRelations(Product product) + protected override async Task FillUpRelationsAsync(Product product) { var sourcesDict = product.Sources.ToDictionary(x => x.Id); foreach (var productSource in product.Sources) { productSource.Product = product; - productSource.Agent = _agentRepo.FindByKey(productSource.AgentKey).NotNull(); + productSource.Agent = (await _agentRepo.FindByKeyAsync(productSource.AgentKey)).NotNull(); } foreach (var productPrice in product.Recent) { diff --git a/PriceChecker.Core/Services/ProductPriceManager.cs b/PriceChecker.Core/Services/ProductPriceManager.cs index 1de6705..5c0a67a 100644 --- a/PriceChecker.Core/Services/ProductPriceManager.cs +++ b/PriceChecker.Core/Services/ProductPriceManager.cs @@ -155,7 +155,7 @@ private async Task ScanForPricesAsync(Product product, bool ignoreRecentDate, Ca } product.Lowest = lowest; - _productRepo.Store(product); + await _productRepo.StoreAsync(product); _eventBus.Publish(new ProductScannedEvent(product.Id, status)); } diff --git a/PriceChecker.UI.Tests/ViewModels/MainViewModelTests.cs b/PriceChecker.UI.Tests/ViewModels/MainViewModelTests.cs index 057cf26..f3c9778 100644 --- a/PriceChecker.UI.Tests/ViewModels/MainViewModelTests.cs +++ b/PriceChecker.UI.Tests/ViewModels/MainViewModelTests.cs @@ -2,6 +2,7 @@ using System.Windows.Shell; using Genius.Atom.UI.Forms; using Genius.Atom.UI.Forms.TestingUtil; +using Genius.Atom.UI.Forms.ViewModels; using Genius.PriceChecker.UI.Helpers; using Genius.PriceChecker.UI.ViewModels; @@ -12,7 +13,7 @@ public class MainViewModelTests : TestBase private readonly TabMock _trackerMock = new(); private readonly TabMock _agentsMock = new(); private readonly TabMock _settingsMock = new(); - private readonly TabMock _logsMock = new(); + private readonly TabMock _logsMock = new(); private readonly Mock _scanContextMock = new(); private readonly Mock _notifyViewModelMock = new(); diff --git a/PriceChecker.UI/App.xaml b/PriceChecker.UI/App.xaml index 85afb9c..b0e2a8c 100644 --- a/PriceChecker.UI/App.xaml +++ b/PriceChecker.UI/App.xaml @@ -19,21 +19,10 @@ - - - - - - - - - - - + - diff --git a/PriceChecker.UI/App.xaml.cs b/PriceChecker.UI/App.xaml.cs index 714098f..c29adc8 100644 --- a/PriceChecker.UI/App.xaml.cs +++ b/PriceChecker.UI/App.xaml.cs @@ -1,7 +1,7 @@ -global using Genius.Atom.Infrastructure; +global using System.Windows; +global using Genius.Atom.Infrastructure; using System.Diagnostics.CodeAnalysis; -using System.Windows; using Genius.PriceChecker.Core.Services; using Genius.PriceChecker.UI.Helpers; using Genius.PriceChecker.UI.ViewModels; @@ -67,7 +67,6 @@ private static void ConfigureServices(IServiceCollection services) services.AddTransient(); services.AddTransient(); services.AddTransient(); - services.AddTransient(); // Services and Helpers: services.AddTransient(); diff --git a/PriceChecker.UI/Assets/Alert32.png b/PriceChecker.UI/Assets/Alert32.png deleted file mode 100644 index 4268fb0..0000000 Binary files a/PriceChecker.UI/Assets/Alert32.png and /dev/null differ diff --git a/PriceChecker.UI/Assets/Copy16.png b/PriceChecker.UI/Assets/Copy16.png deleted file mode 100644 index d131f36..0000000 Binary files a/PriceChecker.UI/Assets/Copy16.png and /dev/null differ diff --git a/PriceChecker.UI/Assets/DonePink16.png b/PriceChecker.UI/Assets/DonePink16.png deleted file mode 100644 index 8a66c39..0000000 Binary files a/PriceChecker.UI/Assets/DonePink16.png and /dev/null differ diff --git a/PriceChecker.UI/Assets/Error16.png b/PriceChecker.UI/Assets/Error16.png deleted file mode 100644 index 9764037..0000000 Binary files a/PriceChecker.UI/Assets/Error16.png and /dev/null differ diff --git a/PriceChecker.UI/Assets/Loading32.gif b/PriceChecker.UI/Assets/Loading32.gif deleted file mode 100644 index 142e487..0000000 Binary files a/PriceChecker.UI/Assets/Loading32.gif and /dev/null differ diff --git a/PriceChecker.UI/Assets/Outdated16.png b/PriceChecker.UI/Assets/Outdated16.png deleted file mode 100644 index 0d60a6e..0000000 Binary files a/PriceChecker.UI/Assets/Outdated16.png and /dev/null differ diff --git a/PriceChecker.UI/Assets/Plus16.png b/PriceChecker.UI/Assets/Plus16.png deleted file mode 100644 index 72036e9..0000000 Binary files a/PriceChecker.UI/Assets/Plus16.png and /dev/null differ diff --git a/PriceChecker.UI/Assets/Refresh16.png b/PriceChecker.UI/Assets/Refresh16.png deleted file mode 100644 index f8e3427..0000000 Binary files a/PriceChecker.UI/Assets/Refresh16.png and /dev/null differ diff --git a/PriceChecker.UI/Assets/Trash16.png b/PriceChecker.UI/Assets/Trash16.png deleted file mode 100644 index 84d434b..0000000 Binary files a/PriceChecker.UI/Assets/Trash16.png and /dev/null differ diff --git a/PriceChecker.UI/Assets/Unknown16.png b/PriceChecker.UI/Assets/Unknown16.png deleted file mode 100644 index eecc8b7..0000000 Binary files a/PriceChecker.UI/Assets/Unknown16.png and /dev/null differ diff --git a/PriceChecker.UI/Assets/Warning16.png b/PriceChecker.UI/Assets/Warning16.png deleted file mode 100644 index 66a7360..0000000 Binary files a/PriceChecker.UI/Assets/Warning16.png and /dev/null differ diff --git a/PriceChecker.UI/Assets/Web16.png b/PriceChecker.UI/Assets/Web16.png deleted file mode 100644 index 8dd4077..0000000 Binary files a/PriceChecker.UI/Assets/Web16.png and /dev/null differ diff --git a/PriceChecker.UI/Helpers/ProductInteraction.cs b/PriceChecker.UI/Helpers/ProductInteraction.cs index b600510..2c1ebad 100644 --- a/PriceChecker.UI/Helpers/ProductInteraction.cs +++ b/PriceChecker.UI/Helpers/ProductInteraction.cs @@ -7,7 +7,7 @@ namespace Genius.PriceChecker.UI.Helpers; public interface IProductInteraction { - void ShowProductInBrowser(ProductSource? productSource); + Task ShowProductInBrowserAsync(ProductSource? productSource); } [ExcludeFromCodeCoverage] @@ -20,17 +20,17 @@ public ProductInteraction(IAgentQueryService agentQuery) _agentQuery = agentQuery; } - public void ShowProductInBrowser(ProductSource? productSource) + public async Task ShowProductInBrowserAsync(ProductSource? productSource) { if (productSource == null) return; - var agentUrl = _agentQuery.FindByKey(productSource.AgentKey)?.Url; - if (agentUrl is null) + var agent = await _agentQuery.FindByKeyAsync(productSource.AgentKey); + if (agent?.Url is null) { return; } - var url = string.Format(agentUrl, productSource.AgentArgument); + var url = string.Format(agent.Url, productSource.AgentArgument); url = url.Replace("&", "^&"); Process.Start(new ProcessStartInfo("cmd", $"/c start {url}") { CreateNoWindow = true }); diff --git a/PriceChecker.UI/ViewModels/LogItemViewModel.cs b/PriceChecker.UI/ViewModels/LogItemViewModel.cs deleted file mode 100644 index d054239..0000000 --- a/PriceChecker.UI/ViewModels/LogItemViewModel.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.ComponentModel; -using System.Windows.Forms; -using System.Windows.Media.Imaging; -using Genius.Atom.UI.Forms; -using Microsoft.Extensions.Logging; - -namespace Genius.PriceChecker.UI.ViewModels; - -public interface ILogItemViewModel : IViewModel -{ - LogLevel Severity { get; } -} - -internal sealed class LogItemViewModel : ViewModelBase, ILogItemViewModel -{ - public LogItemViewModel() - { - CopyToClipboardCommand = new ActionCommand(_ => - Clipboard.SetText(Message)); - } - - [IconSource(nameof(SeverityIcon), 16d)] - public LogLevel Severity { get; set; } - public string Logger { get; set; } = string.Empty; - public string Message { get; set; } = string.Empty; - - [Browsable(false)] - public BitmapImage? SeverityIcon - { - get - { - var icon = Severity switch - { - LogLevel.Warning => "Warning16", - LogLevel.Error => "Error16", - LogLevel.Critical => "Alert32", - {} => null - }; - if (icon is null) - return null; - return (BitmapImage)App.Current.FindResource(icon); - } - } - - [Browsable(false)] - public bool IsSeverityCritical => Severity == LogLevel.Critical; - - [Icon("Copy16")] - public IActionCommand CopyToClipboardCommand { get; } -} diff --git a/PriceChecker.UI/ViewModels/LogsViewModel.cs b/PriceChecker.UI/ViewModels/LogsViewModel.cs deleted file mode 100644 index 16b3f70..0000000 --- a/PriceChecker.UI/ViewModels/LogsViewModel.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.Collections.ObjectModel; -using System.Linq; -using System.Windows; -using Genius.Atom.Infrastructure.Events; -using Genius.Atom.Infrastructure.Logging; -using Genius.Atom.UI.Forms; -using Microsoft.Extensions.Logging; - -namespace Genius.PriceChecker.UI.ViewModels; - -public interface ILogsViewModel : ITabViewModel -{ -} - -internal sealed class LogsViewModel : TabViewModelBase, ILogsViewModel -{ - public LogsViewModel(IEventBus eventBus) - { - eventBus.WhenFired() - .Subscribe(x => { - Application.Current.Dispatcher.Invoke(() => - LogItems.Add(new LogItemViewModel { Severity = x.Severity, Logger = x.Logger, Message = x.Message }) - ); - }); - - CleanLogCommand = new ActionCommand(_ => LogItems.Clear()); - - LogItems.CollectionChanged += (_, args) => { - if (HasNewErrors) - return; - HasNewErrors = args.NewItems?.Cast() - .Any(x => x.Severity >= LogLevel.Error) ?? false; - }; - - Activated.Executed.Subscribe(_ => HasNewErrors = false); - Deactivated.Executed.Subscribe(_ => HasNewErrors = false); - } - - public ObservableCollection LogItems { get; } - = new TypedObservableList(); - - public bool HasNewErrors - { - get => GetOrDefault(false); - set => RaiseAndSetIfChanged(value); - } - - public IActionCommand CleanLogCommand { get; } -} diff --git a/PriceChecker.UI/ViewModels/MainViewModel.cs b/PriceChecker.UI/ViewModels/MainViewModel.cs index 9d92a0e..aa15699 100644 --- a/PriceChecker.UI/ViewModels/MainViewModel.cs +++ b/PriceChecker.UI/ViewModels/MainViewModel.cs @@ -1,6 +1,6 @@ -using System.Collections.Generic; using System.Windows.Shell; using Genius.Atom.UI.Forms; +using Genius.Atom.UI.Forms.ViewModels; using Genius.PriceChecker.UI.Helpers; using Hardcodet.Wpf.TaskbarNotification; @@ -19,7 +19,7 @@ public MainViewModel( ITrackerViewModel tracker, IAgentsViewModel agents, ISettingsViewModel settings, - ILogsViewModel logs, + ILogsTabViewModel logs, ITrackerScanContext scanContext, INotifyIconViewModel notifyViewModel) { diff --git a/PriceChecker.UI/ViewModels/TrackerProductSourceViewModel.cs b/PriceChecker.UI/ViewModels/TrackerProductSourceViewModel.cs index cad9e75..ee632d3 100644 --- a/PriceChecker.UI/ViewModels/TrackerProductSourceViewModel.cs +++ b/PriceChecker.UI/ViewModels/TrackerProductSourceViewModel.cs @@ -1,6 +1,5 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; -using System.Windows; using System.Windows.Media.Imaging; using Genius.Atom.UI.Forms; using Genius.PriceChecker.Core.Models; @@ -19,8 +18,8 @@ public TrackerProductSourceViewModel(IProductInteraction productInteraction, Pro LastPrice = lastPrice; }); - ShowInBrowserCommand = new ActionCommand(_ => - productInteraction.ShowProductInBrowser(productSource)); + ShowInBrowserCommand = new ActionCommand(async _ => + await productInteraction.ShowProductInBrowserAsync(productSource)); } [Browsable(false)] diff --git a/PriceChecker.UI/ViewModels/TrackerProductViewModel.cs b/PriceChecker.UI/ViewModels/TrackerProductViewModel.cs index ca6f07d..a1a8fcb 100644 --- a/PriceChecker.UI/ViewModels/TrackerProductViewModel.cs +++ b/PriceChecker.UI/ViewModels/TrackerProductViewModel.cs @@ -73,8 +73,8 @@ public TrackerProductViewModel(Product? product, IEventBus eventBus, CommitProductCommand = new ActionCommand(_ => CommitProduct()); - ShowInBrowserCommand = new ActionCommand(_ => - productInteraction.ShowProductInBrowser(_product?.Lowest?.ProductSource)); + ShowInBrowserCommand = new ActionCommand(async _ => + await productInteraction.ShowProductInBrowserAsync(_product?.Lowest?.ProductSource)); AddSourceCommand = new ActionCommand(_ => Sources.Add(CreateSourceViewModel(null))); diff --git a/PriceChecker.UI/Views/Logs.xaml b/PriceChecker.UI/Views/Logs.xaml deleted file mode 100644 index 75af4ce..0000000 --- a/PriceChecker.UI/Views/Logs.xaml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - -