public void SummarizeResourcesToFormattedString_1Personal3Devices2ConsumablesDE_PrintsInCorrectFormat() { var personal1 = _captainHookGenerator.GeneratePersonal(); var device1 = _captainHookGenerator.GenerateDevice(); var device2 = _captainHookGenerator.GenerateDevice(); var device3 = _captainHookGenerator.GenerateDevice(); var consumable1 = _captainHookGenerator.GenerateConsumable(); var consumable2 = _captainHookGenerator.GenerateConsumable(); var resourcesList = new ResourceCompilation(); resourcesList.personals.Add(personal1); resourcesList.devices.Add(device1); resourcesList.devices.Add(device2); resourcesList.devices.Add(device3); resourcesList.consumables.Add(consumable1); resourcesList.consumables.Add(consumable2); var summary = MailService.SummarizeResourcesToFormattedString(resourcesList, "de"); Assert.Equal( "6 neue Angebote gefunden:" + Environment.NewLine + "Personal:" + Environment.NewLine + "+ 1 Helfer" + Environment.NewLine + "Geräte:" + Environment.NewLine + "+ 15 PCR Thermocycler" + Environment.NewLine + "Verbrauchsmaterial:" + Environment.NewLine + "+ Schutzkleidung: 80 Packung" + Environment.NewLine, summary ); }
SummarizeResourcesToFormattedString_2Personal3Devices2ConsumablesFromDifferentCategoriesDE_PrintsInCorrectFormat() { var personal1 = _captainHookGenerator.GeneratePersonal(); var personal2 = _anneBonnyGenerator.GeneratePersonal(); var device1 = _anneBonnyGenerator.GenerateDevice(); var device2 = _captainHookGenerator.GenerateDevice(); var device3 = _captainHookGenerator.GenerateDevice(); var consumable1 = _anneBonnyGenerator.GenerateConsumable(); var consumable2 = _captainHookGenerator.GenerateConsumable(); var resourcesList = new ResourceCompilation(); resourcesList.personals.Add(personal1); resourcesList.personals.Add(personal2); resourcesList.devices.Add(device1); resourcesList.devices.Add(device2); resourcesList.devices.Add(device3); resourcesList.consumables.Add(consumable1); resourcesList.consumables.Add(consumable2); var summary = MailService.SummarizeResourcesToFormattedString(resourcesList, "de"); Assert.Equal( "7 neue Angebote gefunden:" + Environment.NewLine + "Personal:" + Environment.NewLine + "+ 2 Helfer" + Environment.NewLine + "Geräte:" + Environment.NewLine + "+ 10 PCR Thermocycler" + Environment.NewLine + "+ 1 Zentrifuge" + Environment.NewLine + "Verbrauchsmaterial:" + Environment.NewLine + "+ Maske: 20 Stück" + Environment.NewLine + "+ Schutzkleidung: 40 Packung" + Environment.NewLine, summary); }
public void SummarizeResourcesToFormattedString_OneDeviceDE_PrintsInCorrectFormat() { var device = _captainHookGenerator.GenerateDevice(); var resourcesList = new ResourceCompilation(); resourcesList.devices.Add(device); var summary = MailService.SummarizeResourcesToFormattedString(resourcesList, "de"); Assert.Equal("1 neues Angebot gefunden:" + Environment.NewLine + "Geräte:" + Environment.NewLine + "+ 5 PCR Thermocycler" + Environment.NewLine, summary); }
public void SummarizeResourcesToFormattedString_OneConsumableDE_PrintsInCorrectFormat() { var consumable = _captainHookGenerator.GenerateConsumable(); var resourcesList = new ResourceCompilation(); resourcesList.consumables.Add(consumable); var summary = MailService.SummarizeResourcesToFormattedString(resourcesList, "de"); Assert.Equal( "1 neues Angebot gefunden:" + Environment.NewLine + "Verbrauchsmaterial:" + Environment.NewLine + "+ Schutzkleidung: 40 Packung" + Environment.NewLine, summary); }
public async Task SendNotificationAboutNewOffersAsync(string region, RegionSubscription regionSubscription, ResourceCompilation resourceCompilation) { string offersDE = SummarizeResourcesToFormattedString(resourceCompilation, "de"); string offersEN = SummarizeResourcesToFormattedString(resourceCompilation, "en"); await Task.Run(async() => { var subject = ConstructSubjectText(region, "Neue Angebote", "New Offers"); var germanText = $@"Liebe/r {regionSubscription.name}, wir haben neue Angebote für Sie auf PIRAT in der Nähe von {regionSubscription.postal_code}. Sie können sie unter https://pirat-tool.com/{region}/de/suchanfrage finden. {offersDE} Falls Sie die Benachrichtigung beenden wollen oder noch Fragen zu PIRAT haben, melden Sie sich gerne jederzeit unter [email protected]. Beste Grüße, Ihr PIRAT-Team"; var englishText = $@"Dear {regionSubscription.name}, There are new offers on PIRAT for you in the region {regionSubscription.postal_code}. You can find them under https://pirat-tool.com/{region}/en/suchanfrage. {offersEN} If you wish to cancel the subscription or have any questions regarding PIRAT, please contact us at [email protected]. Best regards, your PIRAT-Team"; var content = ConstructEmailText(region, germanText, englishText); await SendMailAsync(regionSubscription.email, subject, content); }); }
public async Task SendEmailsAsync() { const int MAX_DISTANCE = 50; var queryAllSubscriptions = from rs in _context.region_subscription as IQueryable <RegionSubscription> where rs.active select rs; var allSubscriptions = await queryAllSubscriptions.ToListAsync(); var queryAllRecentDevices = from o in _context.offer as IQueryable <OfferEntity> join d in _context.device on o.id equals d.offer_id join a in _context.address on o.address_id equals a.Id where (o.timestamp > DateTime.Now.AddDays(-1)) select new { device = d, address = a }; var allRecentDevices = await queryAllRecentDevices.ToListAsync(); var queryAllRecentConsumables = from o in _context.offer as IQueryable <OfferEntity> join c in _context.consumable on o.id equals c.offer_id join a in _context.address on o.address_id equals a.Id where (o.timestamp > DateTime.Now.AddDays(-1)) select new { consumable = c, address = a }; var allRecentConsumables = await queryAllRecentConsumables.ToListAsync(); var queryAllRecentPersonnel = from o in _context.offer as IQueryable <OfferEntity> join p in _context.personal on o.id equals p.offer_id join a in _context.address on o.address_id equals a.Id where (o.timestamp > DateTime.Now.AddDays(-1)) select new { personnel = p, address = a }; var allRecentPersonnel = await queryAllRecentPersonnel.ToListAsync(); var postal_codeToSubscriptionsDictionary = new Dictionary <string, List <RegionSubscription> >(); var postal_codeToResources = new Dictionary <string, ResourceCompilation>(); // Group subscriptions by postal code foreach (RegionSubscription subscription in allSubscriptions) { var ss = postal_codeToSubscriptionsDictionary.GetValueOrDefault(subscription.postal_code, new List <RegionSubscription>()); ss.Add(subscription); postal_codeToSubscriptionsDictionary[subscription.postal_code] = ss; } // Prepare data structures foreach (var(postal_code, _) in postal_codeToSubscriptionsDictionary) { postal_codeToResources[postal_code] = new ResourceCompilation(); } // Compute the distance between all recently offered resources to the relevant postal codes // and assign the resources to the postal codes if they are in close proximity. foreach (var da in allRecentDevices) { foreach (var(postal_code, ss) in postal_codeToSubscriptionsDictionary) { double distance = ComputeDistance(da.address.Latitude, da.address.Longitude, ss[0].latitude, ss[0].longitude); if (distance <= MAX_DISTANCE) { postal_codeToResources[postal_code].devices.Add(new Device().Build(da.device)); } } } foreach (var ca in allRecentConsumables) { foreach (var(postal_code, ss) in postal_codeToSubscriptionsDictionary) { double distance = ComputeDistance(ca.address.Latitude, ca.address.Longitude, ss[0].latitude, ss[0].longitude); if (distance <= MAX_DISTANCE) { postal_codeToResources[postal_code].consumables.Add(new Consumable().build(ca.consumable)); } } } foreach (var pa in allRecentPersonnel) { foreach (var(postal_code, ss) in postal_codeToSubscriptionsDictionary) { double distance = ComputeDistance(pa.address.Latitude, pa.address.Longitude, ss[0].latitude, ss[0].longitude); if (distance <= MAX_DISTANCE) { postal_codeToResources[postal_code].personals.Add(new Personal().build(pa.personnel)); } } } // Send emails foreach (RegionSubscription subscription in allSubscriptions) { ResourceCompilation resources = postal_codeToResources[subscription.postal_code]; if (!resources.isEmpty()) { await this._mailService.SendNotificationAboutNewOffersAsync(subscription.region, subscription, postal_codeToResources[subscription.postal_code]); } } }
//TODO refactor this monstrosity of a method public static string SummarizeResourcesToFormattedString(ResourceCompilation resourceCompilation, string language) { NullCheck.ThrowIfNull <ResourceCompilation>(resourceCompilation); var devices = resourceCompilation.devices .GroupBy(device => device.GetCategoryLocalizedName(language)) .OrderBy(k => k.Key) .ToDictionary( entry => entry.Key, entry => entry.ToList().Sum(d => d.amount) ); var consumables = resourceCompilation.consumables .GroupBy(consumable => consumable.GetCategoryLocalizedName(language)) .OrderBy(key => key.Key) .ToDictionary( entry => entry.Key, entry => entry .GroupBy(consumable => consumable.GetUnitLocalizedName(language)) .ToDictionary(entry2 => entry2.Key, entry2 => entry2.ToList().Sum(c => c.amount)) ); if (!devices.Any() && !consumables.Any()) { throw new ArgumentException("Empty resource list"); } StringBuilder newOffers = new StringBuilder(); var newOfferEntryCount = resourceCompilation.personals.Count + resourceCompilation.devices.Count + resourceCompilation.consumables.Count; if (language == "de") { newOffers.AppendLine(newOfferEntryCount + (newOfferEntryCount == 1 ? " neues Angebot gefunden:" : " neue Angebote gefunden:")); } else { newOffers.AppendLine(newOfferEntryCount + (newOfferEntryCount == 1 ? " new offer found:" : " new offers found:")); } if (resourceCompilation.personals.Any()) { newOffers.AppendLine("Personal:"); newOffers.AppendLine("+ " + resourceCompilation.personals.Count + " " + ( resourceCompilation.personals.Count == 1 ? (language == "de" ? "Helfer" : "volunteer") : (language == "de" ? "Helfer" : "volunteers") )); } if (devices.Any()) { newOffers.AppendLine(language == "de" ? "Geräte:" : "Devices:"); foreach (var d in devices) { newOffers.AppendLine("+ " + d.Value + " " + d.Key); } } if (consumables.Any()) { newOffers.AppendLine(language == "de" ? "Verbrauchsmaterial:" : "Consumables:"); foreach (var c in consumables) { var line = $"+ {c.Key}: "; var i = 0; foreach (var unitAmount in c.Value) { if (i > 0) { line += ", "; } line += unitAmount.Value + " " + unitAmount.Key; i++; } newOffers.AppendLine(line); } } return(newOffers.ToString()); }