public async Task <Shared.Store> AddAsync(Uri uri) { var absoluteUrl = uri.AbsoluteUri; var storedStore = storesRepository.Find(store => store.Url == absoluteUrl).FirstOrDefault(); if (storedStore == null) { var dateTime = DateTime.Now; var store = new Store { Name = "Unknown Store", IsEnabled = true, Url = UriHelper.EnsureStoreUrl(absoluteUrl), Added = dateTime, Updated = dateTime, Read = dateTime }; var transaction = PolicyHelper.WaitAndRetry().Execute( () => storesRepository.BeginTransaction(IsolationLevel.Serializable)); storesRepository.Add(store); await storesRepository.SaveChangesAsync(); await transaction.CommitAsync(); return(store.ToDataTransferObject(true)); } return(storedStore?.ToDataTransferObject()); }
public async Task <Shared.Store> AddAsync(Uri uri) { var absoluteUrl = uri.AbsoluteUri; var storedStore = this.storesRepository.Find(store => store.Url == absoluteUrl).FirstOrDefault(); if (storedStore == null) { var dateTime = DateTime.Now; var store = await this.entityScrapper.GetAsync(absoluteUrl); if (store != null) { store.Added = dateTime; store.Updated = dateTime; store.Read = dateTime; var transaction = PolicyHelper.WaitAndRetry().Execute( () => this.storesRepository.BeginTransaction(IsolationLevel.Serializable)); this.storesRepository.Add(store); await this.storesRepository.SaveChangesAsync(); await transaction.CommitAsync(); return(store.ToDataTransferObject(true)); } } return(storedStore?.ToDataTransferObject()); }
public async Task <ActionResult <Product> > Add( [FromServices] IRepository <Models.Product, int> productRepository, [FromServices] IEntityScrapper <Models.Product> entityScrapper, [FromBody] Uri uri) { var absoluteUrl = uri.AbsoluteUri; var storedProduct = productRepository.Find(product => product.Url == absoluteUrl).FirstOrDefault(); if (storedProduct == null) { var dateTime = DateTime.Now; var product = await entityScrapper.GetAsync(absoluteUrl); if (product != null) { product.Added = dateTime; product.Updated = dateTime; product.Read = dateTime; var transaction = PolicyHelper.WaitAndRetry().Execute( () => productRepository.BeginTransaction(IsolationLevel.Serializable)); productRepository.Add(product); await productRepository.SaveChangesAsync(); await transaction.CommitAsync(); return(product.ToDataTransferObject(true)); } } return(storedProduct?.ToDataTransferObject()); }
public async Task <ActionResult <Department> > Add( [FromServices] IRepository <Models.Department, int> departmentRepository, [FromServices] IEntityScraper <Models.Department> departmentScraper, [FromBody] Uri uri) { var absoluteUrl = uri.AbsoluteUri; var storedDepartment = departmentRepository.Find(department => department.Url == absoluteUrl).FirstOrDefault(); if (storedDepartment == null) { var dateTime = DateTime.Now; var department = new Models.Department { Name = "Unknown Department", IsEnabled = true, Url = UriHelper.EnsureDepartmentUrl(absoluteUrl), Added = dateTime, Updated = dateTime, Read = dateTime }; var transaction = PolicyHelper.WaitAndRetry().Execute( () => departmentRepository.BeginTransaction(IsolationLevel.Serializable)); departmentRepository.Add(department); await departmentRepository.SaveChangesAsync(); await transaction.CommitAsync(); return(department.ToDataTransferObject(true)); } return(storedDepartment?.ToDataTransferObject()); }
public static async Task <(bool, Product)> TryRegisterProductAsync(this IRepository <Product, int> productRepository, string absoluteUrl) { Log.Information("Try to register product with Url '{Url}'", absoluteUrl); var product = productRepository.Find(p => p.Url == absoluteUrl).FirstOrDefault(); var registered = false; if (product == null) { var dateTime = DateTime.Now; product = new Product(); { product.Name = "Unknown Product"; product.Url = UriHelper.EnsureProductUrl(absoluteUrl); product.Added = dateTime; product.Updated = dateTime; product.Read = dateTime; product.IsEnabled = true; var transaction = PolicyHelper.WaitAndRetry().Execute( () => productRepository.BeginTransaction(IsolationLevel.Serializable)); productRepository.Add(product); await productRepository.SaveChangesAsync(); await transaction.CommitAsync(); registered = true; } } Log.Information("Product with Url '{Url}' is registered as {Name}", absoluteUrl, product.Name); return(registered, product); }
public async Task Delete([FromServices] IRepository <Models.Department, int> departmentRepository, int id) { var transaction = PolicyHelper.WaitAndRetry() .Execute(() => departmentRepository.BeginTransaction(IsolationLevel.Serializable)); departmentRepository.Delete(department => department.Id == id); await departmentRepository.SaveChangesAsync(); await transaction.CommitAsync(); }
public async Task Delete([FromServices] IRepository <Product, int> productRepository, int id) { var transaction = PolicyHelper.WaitAndRetry() .Execute(() => productRepository.BeginTransaction(IsolationLevel.Serializable)); productRepository.Delete(product => product.Id == id); await productRepository.SaveChangesAsync(); await transaction.CommitAsync(); }
public async Task ExecuteAsync( IRepository <User, int> userRepository, ITelegramBotClient telegramBotClient = null) { if (telegramBotClient == null) { Log.Information("TelegramBotClient is not registered."); return; } Log.Information("Synchronizing users from Telegram."); Update[] updates = null; try { updates = await telegramBotClient.GetUpdatesAsync(-1); } catch (Exception e) { Log.Error(e, "Error retrieving updates from telegram"); } var users = updates ?.Select( update => new User { ChatId = update?.Message?.Chat?.Id ?? -1, Name = update?.Message?.Chat?.Username ?? string.Empty }).Where(user => !string.IsNullOrWhiteSpace(user.Name)) /*.Distinct(new UserEqualityComparer())*/.ToList(); if (users != null) { foreach (var user in users) { var storedUser = userRepository.Find(u => u.Name == user.Name).FirstOrDefault(); if (storedUser != null) { user.Id = storedUser.Id; } var transaction = PolicyHelper.WaitAndRetry().Execute( () => userRepository.BeginTransaction(IsolationLevel.Serializable)); userRepository.TryAddOrUpdate(user, nameof(User.IsEnable)); await userRepository.SaveChangesAsync(); await transaction.CommitAsync(); } } Log.Information("User synchronization from telegram completed"); }
public async Task Enable([FromServices] IRepository <Product, int> productRepository, int id) { var transaction = PolicyHelper.WaitAndRetry() .Execute(() => productRepository.BeginTransaction(IsolationLevel.Serializable)); var product = productRepository.Find(p => p.Id == id).FirstOrDefault(); if (product != null) { product.IsEnabled = true; } await productRepository.SaveChangesAsync(); await transaction.CommitAsync(); }
public async Task <IEnumerable <Store> > Get([FromServices] IRepository <Models.Store, int> storeRepository) { var stores = new List <Store>(); foreach (var storedStore in storeRepository.All()) { var hasChanged = storedStore.Read < storedStore.Updated; var transaction = PolicyHelper.WaitAndRetry() .Execute(() => storeRepository.BeginTransaction(IsolationLevel.Serializable)); storedStore.Read = DateTime.Now; stores.Add(storedStore.ToDataTransferObject(hasChanged)); await storeRepository.SaveChangesAsync(); await transaction.CommitAsync(); } return(stores); }
public async Task <IEnumerable <Shared.Product> > Get([FromServices] IRepository <Product, int> productRepository) { var products = new List <Shared.Product>(); foreach (var storedProduct in productRepository.All()) { var hasChanged = storedProduct.Read < storedProduct.Updated; var transaction = PolicyHelper.WaitAndRetry().Execute( () => productRepository.BeginTransaction(IsolationLevel.Serializable)); storedProduct.Read = DateTime.Now; await productRepository.SaveChangesAsync(); await transaction.CommitAsync(); products.Add(storedProduct.ToDataTransferObject(hasChanged)); } return(products); }
public async Task <IEnumerable <Department> > Get( [FromServices] IRepository <Models.Department, int> departmentRepository) { var departments = new List <Department>(); foreach (var storedDepartment in departmentRepository.All()) { var hasChanged = storedDepartment.Read < storedDepartment.Updated; var transaction = PolicyHelper.WaitAndRetry().Execute( () => departmentRepository.BeginTransaction(IsolationLevel.Serializable)); storedDepartment.Read = DateTime.Now; await departmentRepository.SaveChangesAsync(); await transaction.CommitAsync(); departments.Add(storedDepartment.ToDataTransferObject(hasChanged)); } return(departments); }
public async Task <ActionResult <Department> > Add( [FromServices] IRepository <Models.Department, int> departmentRepository, [FromServices] IEntityScrapper <Models.Department> departmentScrapper, [FromBody] Uri uri) { var absoluteUrl = uri.AbsoluteUri; var storedDepartment = departmentRepository.Find(department => department.Url == absoluteUrl).FirstOrDefault(); if (storedDepartment == null) { var department = await departmentScrapper.GetAsync(absoluteUrl); if (department != null) { var dateTime = DateTime.Now; department.Added = dateTime; department.Updated = dateTime; department.Read = dateTime; var transaction = PolicyHelper.WaitAndRetry().Execute( () => departmentRepository.BeginTransaction(IsolationLevel.Serializable)); departmentRepository.Add(department); await departmentRepository.SaveChangesAsync(); await transaction.CommitAsync(); return(department.ToDataTransferObject(true)); } } if (storedDepartment == null) { return(this.NotFound()); } return(storedDepartment?.ToDataTransferObject()); }
public async Task Execute( IRepository <Department, int> globalDepartmentRepository, IRepository <Product, int> globalProductRepository, IServiceProvider serviceProvider, IHubContext <MessagesHub> messageHubContext, ITelegramBotClient telegramBotClient = null) { Log.Information("Running {Source} Monitor.", AlertSource.Departments); var sourceChanged = false; // TODO: Improve this. var storedDepartments = globalDepartmentRepository.Find(s => s.IsEnabled).ToList(); var disabledProducts = globalProductRepository.Find(p => !p.IsEnabled).Select(p => p.Url) .ToImmutableSortedSet(); await storedDepartments.ParallelForEachAsync( async storedDepartment => { var serviceScope = serviceProvider.CreateScope(); var serviceScopeServiceProvider = serviceScope.ServiceProvider; var departmentRepository = serviceScopeServiceProvider.GetService <IRepository <Department, int> >(); var userRepository = serviceScopeServiceProvider.GetService <IRepository <User, int> >(); var departmentScrapper = serviceProvider.GetService <IEntityScraper <Department> >(); // var storedDepartmentStore = storedDepartment.Store; // var storedDepartmentName = storedDepartment.Name; // var disabledProducts = productRepository.Find(p => p.Store == storedDepartmentStore && p.Department == storedDepartmentName && !p.IsEnabled) // .Select(p => p.Url).ToImmutableSortedSet(); var dateTime = DateTime.Now; var department = await departmentScrapper.GetAsync( storedDepartment.Url, true, disabledProducts); IDbContextTransaction transaction = null; Log.Information("Updating scrapped department '{url}'", storedDepartment.Url); if (department == null) { department = storedDepartment; if (department.IsAvailable) { transaction = PolicyHelper.WaitAndRetry().Execute( () => departmentRepository.BeginTransaction(IsolationLevel.Serializable)); department.IsAvailable = false; department.Updated = dateTime; department.Sha256 = JsonSerializer.Serialize(department).ComputeSha256(); sourceChanged = true; Log.Information( "Department {Department} from {Store} has changed. Is Available: {IsAvailable}", department.Name, department.Store, department.IsAvailable); } } else if (department.Sha256 != storedDepartment.Sha256) { transaction = PolicyHelper.WaitAndRetry().Execute( () => departmentRepository.BeginTransaction(IsolationLevel.Serializable)); department.Id = storedDepartment.Id; department.Updated = dateTime; departmentRepository.TryAddOrUpdate( department, nameof(Department.Added), nameof(Department.Read)); sourceChanged = true; Log.Information( "Department {Department} from {Store} has changed. Is Available: {IsAvailable}", department.Name, department.Store, department.IsAvailable); } if (transaction != null) { await departmentRepository.SaveChangesAsync(); await transaction.CommitAsync(); // var repository = serviceProvider.GetService<IRepository<Product, int>>(); // foreach (var departmentProduct in department.Products.Values) // { // var departmentProductUrl = departmentProduct.Url; // repository.TryAddOrUpdate(departmentProduct); // } var departmentDataTransferObject = department.ToDataTransferObject(true); var message = JsonSerializer.Serialize(departmentDataTransferObject); await messageHubContext.Clients.All.SendAsync( ClientMethods.EntityChanged, AlertSource.Departments, message); using var httpClient = new HttpClient(); foreach (var departmentProduct in department.Products.Values) { var imageStream = await httpClient.GetStreamAsync(departmentProduct.ImageUrl); var storeSlug = UriHelper.GetStoreSlug(department.Url); if (!Directory.Exists($"logs/products/{storeSlug}")) { Directory.CreateDirectory($"logs/products/{storeSlug}"); } var baseFilePath = $"logs/products/{storeSlug}/{departmentProduct.Name.ComputeSha256()}"; var imageFilePath = $"{baseFilePath}.jpg"; try { await using var fileStream = File.Create(imageFilePath); await imageStream.CopyToAsync(fileStream); await fileStream.FlushAsync(); } catch (Exception e) { Log.Warning(e, "Error saving image."); } var textFilePath = $"{baseFilePath}.txt"; try { var builder = new StringBuilder(); builder.AppendLine(departmentProduct.Name); builder.AppendLine($"{departmentProduct.Price} {departmentProduct.Currency}"); await File.WriteAllTextAsync(textFilePath, builder.ToString()); } catch (Exception e) { Log.Warning(e, "Error saving description"); } } if (telegramBotClient != null && department.IsAvailable) { var messageStringBuilder = new StringBuilder(); messageStringBuilder.AppendLine("*Product Set Changed*"); messageStringBuilder.AppendLine($"*Name:* _{departmentDataTransferObject.Name}_"); messageStringBuilder.AppendLine( $"*Category:* _{departmentDataTransferObject.Category}_"); messageStringBuilder.AppendLine( $"*Products Count:* _{departmentDataTransferObject.ProductsCount}_"); messageStringBuilder.AppendLine( $"*Is Available:* _{departmentDataTransferObject.IsAvailable}_"); if (departmentDataTransferObject.ProductsCount > 0) { messageStringBuilder.AppendLine( $"*Link:* [{departmentDataTransferObject.Url}]({departmentDataTransferObject.Url})"); } // TODO: Use the DTO instead. foreach (var keyValuePair in department.Products) { var product = keyValuePair.Value; messageStringBuilder.AppendLine("------------------------------"); messageStringBuilder.AppendLine($"*Product Name:* {product.Name}"); messageStringBuilder.AppendLine( $"*Product Price:* _{product.Price:C} {product.Currency}_"); messageStringBuilder.AppendLine($"*Product Is Available:* {product.IsAvailable}"); messageStringBuilder.AppendLine($"*Product Is In Cart:* {product.IsInCart}"); if (product.IsAvailable) { // TODO: Improve this to send the image. messageStringBuilder.AppendLine( $"*Product Link:* [{product.Url}]({product.Url})"); messageStringBuilder.AppendLine( $"*Product Image:* [{product.ImageUrl}]({product.ImageUrl})"); } messageStringBuilder.AppendLine("------------------------------"); } messageStringBuilder.AppendLine($"*Store:* _{departmentDataTransferObject.Store}_"); var markdownMessage = messageStringBuilder.ToString(); var users = userRepository.Find(user => user.IsEnable).ToList(); foreach (var user in users) { try { await telegramBotClient.SendTextMessageAsync( user.ChatId, markdownMessage, ParseMode.Markdown); } catch (Exception e) { Log.Warning( e, "Error sending notification messages via telegram to {UserName}", user.Name); } using var client = new HttpClient(); foreach (var departmentProduct in department.Products.Values) { var storeSlug = UriHelper.GetStoreSlug(department.Url); var baseFilePath = $"logs/products/{storeSlug}/{departmentProduct.Name.ComputeSha256()}"; var imageFilePath = $"{baseFilePath}.jpg"; if (File.Exists(imageFilePath)) { try { await telegramBotClient.SendPhotoAsync( user.ChatId, new InputMedia( new FileStream(imageFilePath, FileMode.Open), "photo.jpg"), departmentProduct.Name); } catch (Exception e) { Log.Warning( e, "Error sending detailed messages via telegram to {UserName}", user.Name); } } } } } Log.Information("Entity changed at source {Source}.", AlertSource.Departments); } else { Log.Information("No change detected for department '{url}'", storedDepartment.Url); } }); Log.Information( sourceChanged ? "{Source} changes detected" : "No {Source} changes detected", AlertSource.Departments); }
public async Task Execute( IRepository <Product, int> globalProductRepository, IServiceProvider serviceProvider, IHubContext <MessagesHub> messageHubContext, ITelegramBotClient telegramBotClient = null) { Log.Information("Running {Source} Monitor.", AlertSource.Products); var sourceChanged = false; var storedProducts = globalProductRepository.Find(product => product.IsEnabled).ToList(); await storedProducts.ParallelForEachAsync( async storedProduct => { var serviceScope = serviceProvider.CreateScope(); var serviceScopeServiceProvider = serviceScope.ServiceProvider; var productRepository = serviceScopeServiceProvider.GetService <IRepository <Product, int> >(); var productScrapper = serviceProvider.GetService <IEntityScrapper <Product> >(); var userRepository = serviceScopeServiceProvider.GetService <IRepository <User, int> >(); var dateTime = DateTime.Now; var product = await productScrapper.GetAsync(storedProduct.Url, true); IDbContextTransaction transaction = null; Log.Information("Updating scrapped product '{url}'", storedProduct.Url); if (product == null) { product = storedProduct; if (product.IsAvailable) { transaction = PolicyHelper.WaitAndRetry().Execute( () => productRepository.BeginTransaction(IsolationLevel.Serializable)); product.IsAvailable = false; product.Updated = dateTime; product.Sha256 = JsonSerializer.Serialize(storedProduct).ComputeSHA256(); sourceChanged = true; Log.Information( "Product {Product} from {Store} has changed. Is Available: {IsAvailable}", storedProduct.Name, storedProduct.Store, storedProduct.IsAvailable); } } else if (product.Sha256 != storedProduct.Sha256) { transaction = PolicyHelper.WaitAndRetry().Execute( () => productRepository.BeginTransaction(IsolationLevel.Serializable)); product.Id = storedProduct.Id; product.Updated = dateTime; productRepository.TryAddOrUpdate(product, nameof(Product.Added), nameof(Product.Read)); sourceChanged = true; Log.Information( "Product {Product} from {Store} has changed. Is Available: {IsAvailable}", product.Name, product.Store, product.IsAvailable); } if (transaction != null) { await productRepository.SaveChangesAsync(); await transaction.CommitAsync(); var productDataTransferObject = product.ToDataTransferObject(true); var message = JsonSerializer.Serialize(productDataTransferObject); await messageHubContext.Clients.All.SendAsync( ClientMethods.EntityChanged, AlertSource.Products, message); Log.Information("Entity changed at source {Source}.", AlertSource.Products); if (telegramBotClient != null) { var messageStringBuilder = new StringBuilder(); messageStringBuilder.AppendLine("*Product Changed*"); messageStringBuilder.AppendLine($"*Name:* _{productDataTransferObject.Name}_"); messageStringBuilder.AppendLine( $"*Price:* _{productDataTransferObject.Price.ToString("C")} {productDataTransferObject.Currency}_"); messageStringBuilder.AppendLine( $"*Is Available:* _{productDataTransferObject.IsAvailable}_"); messageStringBuilder.AppendLine( $"*Is In Cart:* _{productDataTransferObject.IsInCart}_"); if (productDataTransferObject.IsAvailable) { messageStringBuilder.AppendLine( $"*Link:* [{productDataTransferObject.Url}]({productDataTransferObject.Url})"); } messageStringBuilder.AppendLine($"*Store:* _{productDataTransferObject.Store}_"); messageStringBuilder.AppendLine( $"*Department:* _{productDataTransferObject.Department}_"); messageStringBuilder.AppendLine( $"*Category:* _{productDataTransferObject.DepartmentCategory}_"); var markdownMessage = messageStringBuilder.ToString(); var users = userRepository.Find(user => user.IsEnable).ToList(); foreach (var user in users) { try { await telegramBotClient.SendTextMessageAsync( user.ChatId, markdownMessage, ParseMode.Markdown); } catch (Exception e) { Log.Error(e, "Error sending message via telegram to {UserName}", user.Name); } } } } }); Log.Information( sourceChanged ? "{Source} changes detected" : "No {Source} changes detected", AlertSource.Products); }
public async Task Execute( IRepository <Department, int> globalDepartmentRepository, IRepository <Product, int> globalProductRepository, IServiceProvider serviceProvider, IHubContext <MessagesHub> messageHubContext, ITelegramBotClient telegramBotClient = null) { Log.Information("Running {Source} Monitor.", AlertSource.Departments); var sourceChanged = false; // TODO: Improve this. var storedDepartments = globalDepartmentRepository.Find(s => s.IsEnabled).ToList(); var disabledProducts = globalProductRepository.Find(p => !p.IsEnabled).Select(p => p.Url) .ToImmutableSortedSet(); await storedDepartments.ParallelForEachAsync( async storedDepartment => { var serviceScope = serviceProvider.CreateScope(); var serviceScopeServiceProvider = serviceScope.ServiceProvider; var departmentRepository = serviceScopeServiceProvider.GetService <IRepository <Department, int> >(); var userRepository = serviceScopeServiceProvider.GetService <IRepository <User, int> >(); var departmentScrapper = serviceProvider.GetService <IEntityScrapper <Department> >(); // var storedDepartmentStore = storedDepartment.Store; // var storedDepartmentName = storedDepartment.Name; // var disabledProducts = productRepository.Find(p => p.Store == storedDepartmentStore && p.Department == storedDepartmentName && !p.IsEnabled) // .Select(p => p.Url).ToImmutableSortedSet(); var dateTime = DateTime.Now; var department = await departmentScrapper.GetAsync( storedDepartment.Url, true, disabledProducts); IDbContextTransaction transaction = null; Log.Information("Updating scrapped department '{url}'", storedDepartment.Url); if (department == null) { department = storedDepartment; if (department.IsAvailable) { transaction = PolicyHelper.WaitAndRetry().Execute( () => departmentRepository.BeginTransaction(IsolationLevel.Serializable)); department.IsAvailable = false; department.Updated = dateTime; department.Sha256 = JsonSerializer.Serialize(department).ComputeSHA256(); sourceChanged = true; Log.Information( "Department {Department} from {Store} has changed. Is Available: {IsAvailable}", department.Name, department.Store, department.IsAvailable); } } else if (department.Sha256 != storedDepartment.Sha256) { transaction = PolicyHelper.WaitAndRetry().Execute( () => departmentRepository.BeginTransaction(IsolationLevel.Serializable)); department.Id = storedDepartment.Id; department.Updated = dateTime; departmentRepository.TryAddOrUpdate( department, nameof(Department.Added), nameof(Department.Read)); sourceChanged = true; Log.Information( "Department {Department} from {Store} has changed. Is Available: {IsAvailable}", department.Name, department.Store, department.IsAvailable); } if (transaction != null) { await departmentRepository.SaveChangesAsync(); await transaction.CommitAsync(); var departmentDataTransferObject = department.ToDataTransferObject(true); var message = JsonSerializer.Serialize(departmentDataTransferObject); await messageHubContext.Clients.All.SendAsync( ClientMethods.EntityChanged, AlertSource.Departments, message); if (telegramBotClient != null && department.IsAvailable) { var messageStringBuilder = new StringBuilder(); messageStringBuilder.AppendLine("*Product Set Changed*"); messageStringBuilder.AppendLine($"*Name:* _{departmentDataTransferObject.Name}_"); messageStringBuilder.AppendLine( $"*Category:* _{departmentDataTransferObject.Category}_"); messageStringBuilder.AppendLine( $"*Products Count:* _{departmentDataTransferObject.ProductsCount}_"); messageStringBuilder.AppendLine( $"*Is Available:* _{departmentDataTransferObject.IsAvailable}_"); if (departmentDataTransferObject.ProductsCount > 0) { messageStringBuilder.AppendLine( $"*Link:* [{departmentDataTransferObject.Url}]({departmentDataTransferObject.Url})"); } // TODO: Use the DTO instead. foreach (var keyValuePair in department.Products) { var product = keyValuePair.Value; messageStringBuilder.AppendLine("------------------------------"); messageStringBuilder.AppendLine($"*Product Name:* {product.Name}"); messageStringBuilder.AppendLine( $"*Product Price:* _{product.Price:C} {product.Currency}_"); messageStringBuilder.AppendLine($"*Product Is Available:* {product.IsAvailable}"); messageStringBuilder.AppendLine($"*Product Is In Cart:* {product.IsInCart}"); if (product.IsAvailable) { messageStringBuilder.AppendLine( $"*Product Link:* [{product.Url}]({product.Url})"); } messageStringBuilder.AppendLine("------------------------------"); } messageStringBuilder.AppendLine($"*Store:* _{departmentDataTransferObject.Store}_"); var markdownMessage = messageStringBuilder.ToString(); var users = userRepository.Find(user => user.IsEnable).ToList(); foreach (var user in users) { try { await telegramBotClient.SendTextMessageAsync( user.ChatId, markdownMessage, ParseMode.Markdown); } catch (Exception e) { Log.Error(e, "Error sending message via telegram to {UserName}", user.Name); } } } Log.Information("Entity changed at source {Source}.", AlertSource.Departments); } else { Log.Information("No change detected for department '{url}'", storedDepartment.Url); } }); // Parallel.ForEach( // storedDepartments, // async storedDepartment => // { // var departmentRepository = serviceProvider.CreateScope().ServiceProvider // .GetService<IRepository<Department, int>>(); // // var storedDepartmentStore = storedDepartment.Store; // // var storedDepartmentName = storedDepartment.Name; // // var disabledProducts = productRepository.Find(p => p.Store == storedDepartmentStore && p.Department == storedDepartmentName && !p.IsEnabled) // // .Select(p => p.Url).ToImmutableSortedSet(); // var dateTime = DateTime.Now; // var department = await departmentScrapper.GetAsync( // storedDepartment.Url, // true, // disabledProducts); // IDbContextTransaction transaction = null; // Log.Information("Updating scrapped department '{url}'", storedDepartment.Url); // if (department == null) // { // department = storedDepartment; // if (department.IsAvailable) // { // transaction = PolicyHelper.WaitAndRetry().Execute( // () => departmentRepository.BeginTransaction(IsolationLevel.Serializable)); // department.IsAvailable = false; // department.Updated = dateTime; // department.Sha256 = JsonSerializer.Serialize(department).ComputeSHA256(); // sourceChanged = true; // Log.Information( // "Department {Department} from {Store} has changed. Is Available: {IsAvailable}", // department.Name, // department.Store, // department.IsAvailable); // } // } // else if (department.Sha256 != storedDepartment.Sha256) // { // transaction = PolicyHelper.WaitAndRetry().Execute( // () => departmentRepository.BeginTransaction(IsolationLevel.Serializable)); // department.Id = storedDepartment.Id; // department.Updated = dateTime; // departmentRepository.TryAddOrUpdate( // department, // nameof(Department.Added), // nameof(Department.Read)); // sourceChanged = true; // Log.Information( // "Department {Department} from {Store} has changed. Is Available: {IsAvailable}", // department.Name, // department.Store, // department.IsAvailable); // } // if (transaction != null) // { // await departmentRepository.SaveChangesAsync(); // await transaction.CommitAsync(); // var departmentDataTransferObject = department.ToDataTransferObject(true); // var message = JsonSerializer.Serialize(departmentDataTransferObject); // await messageHubContext.Clients.All.SendAsync( // ClientMethods.EntityChanged, // AlertSource.Departments, // message); // if (telegramBotClient != null && department.IsAvailable) // { // var messageStringBuilder = new StringBuilder(); // messageStringBuilder.AppendLine("*Product Set Changed*"); // messageStringBuilder.AppendLine($"*Name:* _{departmentDataTransferObject.Name}_"); // messageStringBuilder.AppendLine( // $"*Category:* _{departmentDataTransferObject.Category}_"); // messageStringBuilder.AppendLine( // $"*Products Count:* _{departmentDataTransferObject.ProductsCount}_"); // messageStringBuilder.AppendLine( // $"*Is Available:* _{departmentDataTransferObject.IsAvailable}_"); // if (departmentDataTransferObject.ProductsCount > 0) // { // messageStringBuilder.AppendLine( // $"*Link:* [{departmentDataTransferObject.Url}]({departmentDataTransferObject.Url})"); // } // // TODO: Use the DTO instead. // foreach (var keyValuePair in department.Products) // { // var product = keyValuePair.Value; // messageStringBuilder.AppendLine("------------------------------"); // messageStringBuilder.AppendLine($"*Product Name:* {product.Name}"); // messageStringBuilder.AppendLine( // $"*Product Price:* _{product.Price:C} {product.Currency}_"); // messageStringBuilder.AppendLine($"*Product Is Available:* {product.IsAvailable}"); // messageStringBuilder.AppendLine($"*Product Is In Cart:* {product.IsInCart}"); // if (product.IsAvailable) // { // messageStringBuilder.AppendLine( // $"*Product Link:* [{product.Url}]({product.Url})"); // } // messageStringBuilder.AppendLine("------------------------------"); // } // messageStringBuilder.AppendLine($"*Store:* _{departmentDataTransferObject.Store}_"); // var markdownMessage = messageStringBuilder.ToString(); // var users = userRepository.Find(user => user.IsEnable).ToList(); // foreach (var user in users) // { // try // { // await telegramBotClient.SendTextMessageAsync( // user.ChatId, // markdownMessage, // ParseMode.Markdown); // } // catch (Exception e) // { // Log.Error(e, "Error sending message via telegram to {UserName}", user.Name); // } // } // } // Log.Information("Entity changed at source {Source}.", AlertSource.Departments); // } // else // { // Log.Information("No change detected for department '{url}'", storedDepartment.Url); // } // }); Log.Information( sourceChanged ? "{Source} changes detected" : "No {Source} changes detected", AlertSource.Departments); }