From 161986c246bedc6f257687ad372ad26be5155d45 Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Mon, 7 Mar 2022 20:38:38 +0000 Subject: [PATCH] --- .vscode/launch.json | 2 +- server/AyaNova/biz/QuoteBiz.cs | 4 - server/AyaNova/generator/CoreJobNotify.cs | 96 +++++++++++++++++++++-- 3 files changed, 92 insertions(+), 10 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index f18b4927..d0cceaa8 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -48,7 +48,7 @@ "AYANOVA_DATA_PATH": "c:\\temp\\ravendata", "AYANOVA_USE_URLS": "http://*:7575;", //"AYANOVA_PERMANENTLY_ERASE_DATABASE":"true", - "AYANOVA_SERVER_TEST_MODE": "true", + "AYANOVA_SERVER_TEST_MODE": "false", "AYANOVA_SERVER_TEST_MODE_TZ_OFFSET": "-8", //"AYANOVA_REPORT_RENDERING_TIMEOUT":"1", "AYANOVA_SERVER_TEST_MODE_SEEDLEVEL": "small", diff --git a/server/AyaNova/biz/QuoteBiz.cs b/server/AyaNova/biz/QuoteBiz.cs index e2cee2ce..8ce33ad8 100644 --- a/server/AyaNova/biz/QuoteBiz.cs +++ b/server/AyaNova/biz/QuoteBiz.cs @@ -1293,10 +1293,6 @@ namespace AyaNova.Biz //Object tags must match and Customer tags must match if (NotifyEventHelper.ObjectHasAllSubscriptionTags(QuoteInfo.Tags, sub.Tags) && NotifyEventHelper.ObjectHasAllSubscriptionTags(custInfo.Tags, sub.CustomerTags)) { - - - - CustomerNotifyEvent n = new CustomerNotifyEvent() { EventType = NotifyEventType.QuoteStatusChange, diff --git a/server/AyaNova/generator/CoreJobNotify.cs b/server/AyaNova/generator/CoreJobNotify.cs index 84f69c2d..fccdc2a5 100644 --- a/server/AyaNova/generator/CoreJobNotify.cs +++ b/server/AyaNova/generator/CoreJobNotify.cs @@ -67,6 +67,7 @@ namespace AyaNova.Biz } } + #region User notification subscription events using (AyContext ct = AyaNova.Util.ServiceProviderProvider.DBContext) { var events = await ct.NotifyEvent.AsNoTracking().ToListAsync(); @@ -136,6 +137,91 @@ namespace AyaNova.Biz } } } + #endregion user notification events + + + #region Customer 'proxy' notification subscription events + using (AyContext ct = AyaNova.Util.ServiceProviderProvider.DBContext) + { + var customerevents = await ct.CustomerNotifyEvent.AsNoTracking().ToListAsync(); + log.LogDebug($"Found {customerevents.Count} CustomerNotifyEvents to examine for potential delivery"); + + //iterate and deliver + foreach (var customernotifyevent in customerevents) + { + //no notifications for inactive users, just delete it as if it was delivered + var CustInfo = await ct.Customer.AsNoTracking().Where(x => x.Id == customernotifyevent.CustomerId).Select(x => new {x.Name, x.Active, x.Tags, x.EmailAddress }).FirstOrDefaultAsync(); + + + if (!CustInfo.Active) + { + log.LogDebug($"Inactive Customer {CustInfo.Name}, removing notify rather than delivering it: {customernotifyevent}"); + ct.CustomerNotifyEvent.Remove(customernotifyevent); + await ct.SaveChangesAsync(); + continue; + } + + if (string.IsNullOrWhiteSpace(CustInfo.EmailAddress)) + { + log.LogDebug($"Customer {CustInfo.Name} has no email address, removing notify rather than delivering it: {customernotifyevent}"); + ct.CustomerNotifyEvent.Remove(customernotifyevent); + await ct.SaveChangesAsync(); + continue; + } + + //Get subscription for delivery + var Subscription = await ct.NotifySubscription.AsNoTracking().FirstOrDefaultAsync(x => x.Id == customernotifyevent.NotifySubscriptionId); + + //NOTE: There is no need to separate out future delivery and immediate delivery because + // All events have an event date, it's either immediate upon creation or it's future + // but not all events have an age value including ones with future event dates, + // and the default agevalue and advancenotice are both zero regardless so the block below works for either future or immediate deliveries + + var deliverAfter = customernotifyevent.EventDate + Subscription.AgeValue - Subscription.AdvanceNotice; + if (deliverAfter < DateTime.UtcNow) + { + //Check "circuit breaker" for notification types that could + //repeat rapidly + //(e.g. pm notification error for a fucked up PM that is attempted every few minutes or a + //system exception for something that pops up every few minutes or a thousand times in a hour etc) + //Don't check for ones that are regular object based + //which can and will properly send out the same notification regularly + //(e.g. workorder status change into out of and back into the same staus) + switch (customernotifyevent.EventType) + { + case NotifyEventType.BackupStatus: + case NotifyEventType.GeneralNotification: + case NotifyEventType.ServerOperationsProblem: + case NotifyEventType.PMGenerationFailed: + { + //check if we've just delivered this same thing in the last 12 hours which is the hard limit (case 3917) + var twelvehoursago = DateTime.UtcNow - new TimeSpan(12, 0, 0); + + //look for same delivery less than last12hours ago + if (await ct.NotifyDeliveryLog.AnyAsync(z => z.Processed > twelvehoursago && z.NotifySubscriptionId == customernotifyevent.NotifySubscriptionId && z.ObjectId == customernotifyevent.ObjectId)) + { + log.LogDebug($"Notification event will not be delivered: repetitive (server system event type and delivered at least once in the last 12 hours to this subscriber: {customernotifyevent})"); + ct.NotifyEvent.Remove(customernotifyevent); + await ct.SaveChangesAsync(); +#if (DEBUG) + log.LogInformation($"DeliverInApp event will not be delivered: repetitive (server system event type and delivered at least once in the last 12 hours to this subscriber: {customernotifyevent})"); +#endif + continue; + } + } + break; + } + + //Do the delivery, it's kosher + if (Subscription.DeliveryMethod == NotifyDeliveryMethod.App) + await DeliverInApp(customernotifyevent, Subscription.AgeValue, ct); + else if (Subscription.DeliveryMethod == NotifyDeliveryMethod.SMTP) + await DeliverSMTP(customernotifyevent, Subscription.AgeValue, Subscription.AdvanceNotice, Subscription.DeliveryAddress, ct); + } + } + } + #endregion customer notification events + } catch (Exception ex) { @@ -343,9 +429,9 @@ namespace AyaNova.Biz //generate a workorder report here get the path and send it with the message using (AyContext ct = AyaNova.Util.ServiceProviderProvider.DBContext) { - long overrideLanguageId=2; + long overrideLanguageId = 2; - ReportBiz biz = new ReportBiz(ct,1,overrideLanguageId,AuthorizationRoles.BizAdmin); + ReportBiz biz = new ReportBiz(ct, 1, overrideLanguageId, AuthorizationRoles.BizAdmin); //example with workorder report //{"AType":34,"selectedRowIds":[355],"ReportId":9,"ClientMeta":{"UserName":"AyaNova SuperUser","Authorization":"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxNjQ2NzgyNTc4IiwiaXNzIjoiYXlhbm92YS5jb20iLCJpZCI6IjEifQ.ad7Acq54JCRGitDWKDJFFnqKkidbdaKaFmj-RA_RG5E","DownloadToken":"NdoU8ca3LG4L39Tj2oi3UReeeM7FLevTgbgopTPhGbA","TimeZoneName":"America/Los_Angeles","LanguageName":"en-US","Hour12":true,"CurrencyName":"USD","DefaultLocale":"en","PDFDate":"3/3/22","PDFTime":"3:38 PM"}} @@ -356,8 +442,8 @@ namespace AyaNova.Biz var jwt = Api.Controllers.AuthController.GenRpt(overrideLanguageId); //this could be adjusted by culture if we allow user to set a culture but that's getting a bit into the weeds, likely the server default is fine - var pdfDate=new DateTime().ToShortDateString(); - var pdfTime=new DateTime().ToShortTimeString(); + var pdfDate = new DateTime().ToShortDateString(); + var pdfTime = new DateTime().ToShortTimeString(); reportRequest.ClientMeta = JToken.Parse($"{{'UserName':'-','Authorization':'Bearer {jwt}','TimeZoneName':'America/Los_Angeles','LanguageName':'en-US','Hour12':true,'CurrencyName':'USD','DefaultLocale':'en','PDFDate':'{pdfDate}','PDFTime':'{pdfTime}'}}"); //get port number @@ -378,7 +464,7 @@ namespace AyaNova.Biz switch (status) { case JobStatus.Completed: - { + { //get job logs and parse file name from it JobOperationsBiz jobopsbiz = new JobOperationsBiz(ct, 1, AuthorizationRoles.BizAdmin); List log = await jobopsbiz.GetJobLogListAsync((Guid)jobid);