diff --git a/server/AyaNova/generator/CoreJobNotify.cs b/server/AyaNova/generator/CoreJobNotify.cs index 59dc6578..56b63eeb 100644 --- a/server/AyaNova/generator/CoreJobNotify.cs +++ b/server/AyaNova/generator/CoreJobNotify.cs @@ -19,9 +19,6 @@ namespace AyaNova.Biz { private static bool NotifyIsRunning = false; private static ILogger log = AyaNova.Util.ApplicationLogging.CreateLogger("CoreJobNotify"); - - - private static DateTime lastRun = DateTime.MinValue; private static DateTime lastNotifyHealthCheckSentLocal = DateTime.MinValue; private static TimeSpan TS_24_HOURS = new TimeSpan(24, 0, 0);//used to ensure daily ops happen no more than that @@ -32,12 +29,6 @@ namespace AyaNova.Biz private static TimeSpan RUN_EVERY_INTERVAL = new TimeSpan(0, 2, 0);//no more frequently than once every 2 minutes #endif - //temporary list to hold translations as required during delivery - private static Dictionary> _NotifyEventTypeTransCache = new Dictionary>(); - private static Dictionary> _AyaTypeTypeTransCache = new Dictionary>(); - private static Dictionary _UserTranslationIdCache = new Dictionary(); - private static Dictionary _ServerTheWordTranslations = new Dictionary(); - //////////////////////////////////////////////////////////////////////////////////////////////// // DoSweep // @@ -52,7 +43,7 @@ namespace AyaNova.Biz //This will get triggered roughly every minute, but we don't want to deliver that frequently if (DateTime.UtcNow - lastRun < RUN_EVERY_INTERVAL) { - log.LogTrace($"Notify ran less than {RUN_EVERY_INTERVAL}, exiting this cycle"); + log.LogTrace($"Notify ran less than {RUN_EVERY_INTERVAL} ago, exiting this cycle"); return; } try @@ -79,29 +70,10 @@ namespace AyaNova.Biz using (AyContext ct = AyaNova.Util.ServiceProviderProvider.DBContext) - { + { var events = await ct.NotifyEvent.AsNoTracking().ToListAsync(); log.LogTrace($"Found {events.Count} NotifyEvents to examine for potential delivery"); - - - //########################### - //TODO: All this needs to be moved into smtp delivery and cache populated on demand rather than up front - // //cache translations - // //Get all subscription unique userId's that aren't inapp deliveries - // var usersNeedingTranslations = events.Where(z => z.NotifySubscription.DeliveryMethod != NotifyDeliveryMethod.App && z.User.Active).Select(z => z.NotifySubscription.UserId).ToList().Distinct(); - // foreach (long userid in usersNeedingTranslations) - // { - // var usr = await ct.User.AsNoTracking().Include(z => z.UserOptions).SingleAsync(z => z.Id == userid); - // long transId = usr.UserOptions.TranslationId; - - // _UserTranslationIdCache.Add(userid, transId); - // await CacheTranslations(transId, usr.Roles); - // } - // //cache all translations of the word "Server" for server notifications - // _ServerTheWordTranslations = await TranslationBiz.GetAllTranslationsForKey("Server"); - //################################ - //iterate and deliver foreach (var notifyevent in events) { @@ -140,10 +112,7 @@ namespace AyaNova.Biz } finally { - log.LogTrace("Notify is done setting to not running state and tagging lastRun timestamp"); - _UserTranslationIdCache.Clear(); - _NotifyEventTypeTransCache.Clear(); - _AyaTypeTypeTransCache.Clear(); + log.LogTrace("Notify is done setting to not running state and tagging lastRun timestamp"); lastRun = DateTime.UtcNow; NotifyIsRunning = false; @@ -151,36 +120,6 @@ namespace AyaNova.Biz } - //cache any translations required for email notification - private static async Task CacheTranslations(long translationId, AuthorizationRoles roles) - { - if (!_NotifyEventTypeTransCache.ContainsKey(translationId)) - _NotifyEventTypeTransCache.Add(translationId, await AyaNova.Api.Controllers.EnumListController.GetEnumList( - "NotifyEventType", - translationId, - roles)); - - if (!_AyaTypeTypeTransCache.ContainsKey(translationId)) - _AyaTypeTypeTransCache.Add( - translationId, - await AyaNova.Api.Controllers.EnumListController.GetEnumList( - "AyaType", - translationId, - roles)); - - } - - //Used for subject of email and message deliveries - private static string GetTranslatedNotifyEventName(NotifyEventType net, long translationId) - { - return _NotifyEventTypeTransCache.First(z => z.Key == translationId).Value.First(z => z.Id == (int)net).Name; - } - - private static string GetTranslatedAyaTypeName(AyaType at, long translationId) - { - return _AyaTypeTypeTransCache.First(z => z.Key == translationId).Value.First(z => z.Id == (int)at).Name; - } - private static async Task DeliverInApp(NotifyEvent ne, AyContext ct) { log.LogTrace($"DeliverInApp notify event: {ne}"); @@ -188,65 +127,72 @@ namespace AyaNova.Biz await ct.SaveChangesAsync(); ct.NotifyEvent.Remove(ne); await ct.SaveChangesAsync(); - } private static async Task DeliverSMTP(NotifyEvent ne, NotifySubscription sub, AyContext ct) { - - //TODO: UNCOMMENT THE FOLLOWING AND ADD CACHING AS PER ABOVE - log.LogTrace($"DeliverSMTP delivering notify event: {ne}"); - if (string.IsNullOrWhiteSpace(sub.DeliveryAddress)) - await NotifyEventHelper.AddGeneralNotifyEvent(NotifyEventType.GeneralNotification, $"No email address is set in subscription to deliver email notification for this event:{ne}", "Error", null, ne.UserId); - - - - - var transid = _UserTranslationIdCache[sub.UserId]; - var name = ne.Name; - if (name == "~SERVER~") - name = _ServerTheWordTranslations.First(z => z.Key == transid).Value; - - - //AyaType translation - var AyaTypeTranslated = string.Empty; - if (ne.AyaType != AyaType.NoType) - AyaTypeTranslated = $":{GetTranslatedAyaTypeName(ne.AyaType, transid)}"; - - var subject = $"AY{AyaTypeTranslated}:{GetTranslatedNotifyEventName(ne.EventType, transid)}:{name}"; - - //subscription link translation - var SubscriptionTypeName = GetTranslatedAyaTypeName(AyaType.NotifySubscription, transid); - - IMailer m = AyaNova.Util.ServiceProviderProvider.Mailer; try { - var body = ""; - //NOTE: if need any other exemptions besides backup status make a separate static function "CanOpen(NotifyEventType)" - - if (ne.ObjectId != 0 || ne.EventType == NotifyEventType.BackupStatus) + log.LogTrace($"DeliverSMTP delivering notify event: {ne}"); + if (string.IsNullOrWhiteSpace(sub.DeliveryAddress)) { - body = OpenObjectUrlBuilder(ne.AyaType, ne.ObjectId, ne.EventType) + "\n"; - } - body += ne.Message; - - //Add link to subscription - //http://localhost:8080/open/51/1 //add subscription link, notifysub is object type 51 - if (!body.EndsWith('\n')) - body += "\n"; - - body += $"-----\n({SubscriptionTypeName}: {OpenSubscriptionUrlBuilder(ne.NotifySubscriptionId)} )\n"; - - if (!ServerGlobalOpsSettingsCache.Notify.SmtpDeliveryActive) - { - await NotifyEventHelper.AddGeneralNotifyEvent(NotifyEventType.GeneralNotification, $"Email notifications are set to OFF at server, unable to send email notification for this event:{ne}", "Error", null, ne.UserId); - log.LogInformation($"** WARNING: SMTP notification is currently set to Active=False; unable to deliver email notification, re-routed to in-app notification instead [UserId={ne.UserId}, Notify subscription={ne.NotifySubscriptionId}]. Change this setting or have users remove email delivery notifications if this is permanent **"); + await NotifyEventHelper.AddGeneralNotifyEvent(NotifyEventType.GeneralNotification, $"No email address is set in subscription to deliver email notification. This event will be removed from the delivery queue as undeliverable: {ne}", "Error", null, ne.UserId); } else { - await m.SendEmailAsync(sub.DeliveryAddress, subject, body, ServerGlobalOpsSettingsCache.Notify); + //Email notification requires pre-translated values + List TranslationKeysToFetch = new List(); + TranslationKeysToFetch.Add(ne.AyaType.ToString()); + if (ne.Name == "~SERVER~") + TranslationKeysToFetch.Add("Server"); + var EventTypeTranslationKey = "NotifyEvent" + ne.EventType.ToString(); + TranslationKeysToFetch.Add(EventTypeTranslationKey); + var transid = await ct.UserOptions.AsNoTracking().Where(x => x.UserId == sub.UserId).Select(x => x.TranslationId).FirstOrDefaultAsync(); + var LT = await TranslationBiz.GetSubsetStaticAsync(TranslationKeysToFetch, transid); + + var name = ne.Name; + if (name == "~SERVER~") + name = LT["Server"]; + + //AyaType translation + var AyaTypeTranslated = string.Empty; + if (ne.AyaType != AyaType.NoType) + AyaTypeTranslated = $":{LT[ne.AyaType.ToString()]}"; + + var subject = $"AY{AyaTypeTranslated}:{LT[EventTypeTranslationKey]}:{name}"; + + //subscription link translation + var SubscriptionTypeName = AyaTypeTranslated; + + IMailer m = AyaNova.Util.ServiceProviderProvider.Mailer; + + var body = ""; + //NOTE: if need any other exemptions besides backup status make a separate static function "CanOpen(NotifyEventType)" + + if (ne.ObjectId != 0 || ne.EventType == NotifyEventType.BackupStatus) + { + body = OpenObjectUrlBuilder(ne.AyaType, ne.ObjectId, ne.EventType) + "\n"; + } + body += ne.Message; + + //Add link to subscription + //http://localhost:8080/open/51/1 //add subscription link, notifysub is object type 51 + if (!body.EndsWith('\n')) + body += "\n"; + + body += $"-----\n({SubscriptionTypeName}: {OpenSubscriptionUrlBuilder(ne.NotifySubscriptionId)} )\n"; + + if (!ServerGlobalOpsSettingsCache.Notify.SmtpDeliveryActive) + { + await NotifyEventHelper.AddGeneralNotifyEvent(NotifyEventType.GeneralNotification, $"Email notifications are set to OFF at server, unable to send email notification for this event:{ne}", "Error", null, ne.UserId); + log.LogInformation($"** WARNING: SMTP notification is currently set to Active=False; unable to deliver email notification, re-routed to in-app notification instead [UserId={ne.UserId}, Notify subscription={ne.NotifySubscriptionId}]. Change this setting or have users remove email delivery notifications if this is permanent **"); + } + else + { + await m.SendEmailAsync(sub.DeliveryAddress, subject, body, ServerGlobalOpsSettingsCache.Notify); + } } } catch (Exception ex)