diff --git a/server/AyaNova/Controllers/NotifyController.cs b/server/AyaNova/Controllers/NotifyController.cs index 03bd0fd3..6dd0ee53 100644 --- a/server/AyaNova/Controllers/NotifyController.cs +++ b/server/AyaNova/Controllers/NotifyController.cs @@ -1,3 +1,4 @@ +using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; @@ -133,21 +134,21 @@ namespace AyaNova.Api.Controllers return BadRequest(new ApiErrorResponse(ModelState)); } - var ret = await ct.NotifyEvent.AsNoTracking().Include(z => z.NotifySubscription).Include(z=>z.User).Select(z => new + var ret = new List(); + var NotifyEvents = await ct.NotifyEvent.AsNoTracking().ToListAsync(); + foreach (NotifyEvent ne in NotifyEvents) { - z.Id, - z.Created, - z.EventDate, - DeliverAfter = (z.EventDate + z.NotifySubscription.AgeValue - z.NotifySubscription.AdvanceNotice), - z.UserId, - user=z.User.Name, - z.EventType, - z.AyaType, - z.Name - }).ToListAsync(); + var UserInfo = await ct.User.AsNoTracking().Where(x => x.Id == ne.UserId).Select(x => new { Active = x.Active, Name = x.Name }).FirstOrDefaultAsync(); + var Subscription = await ct.NotifySubscription.AsNoTracking().FirstOrDefaultAsync(x => x.Id == ne.NotifySubscriptionId); + + ret.Add(new NotifyEventQueueItem(ne.Id, ne.Created, ne.EventDate, (ne.EventDate + Subscription.AgeValue - Subscription.AdvanceNotice), ne.UserId, UserInfo.Name, ne.EventType, ne.AyaType, ne.Name)); + } + return Ok(ApiOkResponse.Response(ret)); } + public record NotifyEventQueueItem(long Id, DateTime Created, DateTime EventDate, DateTime DeliverAfter, long UserId, string User, NotifyEventType EventType, AyaType AyaType, string Name); + /// /// Delete pending notification event /// diff --git a/server/AyaNova/generator/CoreJobNotify.cs b/server/AyaNova/generator/CoreJobNotify.cs index 40edfaec..8a56c692 100644 --- a/server/AyaNova/generator/CoreJobNotify.cs +++ b/server/AyaNova/generator/CoreJobNotify.cs @@ -104,36 +104,46 @@ namespace AyaNova.Biz //All items have an event date, for non time delayed events it's just the moment it was created //which will predate this moment now if it's pre-existing - var events = await ct.NotifyEvent.Include(z => z.User).Include(z => z.NotifySubscription).AsNoTracking().ToListAsync(); + //var events = await ct.NotifyEvent.AsNoTracking().Include(z => z.User).Include(z => z.NotifySubscription).ToListAsync(); + var events = await ct.NotifyEvent.AsNoTracking().ToListAsync(); log.LogTrace($"Found {events.Count} NotifyEvents to examine for potential delivery"); - //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"); + + //########################### + //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) { //no notifications for inactive users, just delete it as if it was delivered - if (!notifyevent.User.Active) + // if (!notifyevent.User.Active) + var UserInfo = await ct.User.AsNoTracking().Where(x => x.Id == notifyevent.UserId).Select(x => new { Active = x.Active, Name = x.Name }).FirstOrDefaultAsync(); + if (!UserInfo.Active) { - log.LogTrace($"Inactive user {notifyevent.User.Name}, removing notify rather than delivering it: {notifyevent}"); + log.LogTrace($"Inactive user {UserInfo.Name}, removing notify rather than delivering it: {notifyevent}"); ct.NotifyEvent.Remove(notifyevent); await ct.SaveChangesAsync(); continue; } + //Get subscription for delivery + var Subscription = await ct.NotifySubscription.AsNoTracking().FirstOrDefaultAsync(x => x.Id == notifyevent.NotifySubscriptionId); //TIME DELAYED AGED EVENT? //when to time delay deliver formula:If sub.agevalue!= timespan.zero then deliver on = @@ -147,36 +157,17 @@ namespace AyaNova.Biz // All events have an event date, it's either immediate upon creation or it's future //but not all events ahve 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 - // if (notifyevent.NotifySubscription.AgeValue != TimeSpan.Zero) - // { - var deliverAfter = notifyevent.EventDate + notifyevent.NotifySubscription.AgeValue - notifyevent.NotifySubscription.AdvanceNotice; - if (deliverAfter < DateTime.UtcNow) - { - if (notifyevent.NotifySubscription.DeliveryMethod == NotifyDeliveryMethod.App) - { - await DeliverInApp(notifyevent, ct); - } - if (notifyevent.NotifySubscription.DeliveryMethod == NotifyDeliveryMethod.SMTP) - { - await DeliverSMTP(notifyevent, ct); - } - } - // } - // else - // { - // //COULD BE TIME DELAYED BUT WITHOUT AGE, i.e. EventDate takes precedence? + var deliverAfter = notifyevent.EventDate + Subscription.AgeValue - Subscription.AdvanceNotice; + if (deliverAfter < DateTime.UtcNow) + { + if (Subscription.DeliveryMethod == NotifyDeliveryMethod.App) + await DeliverInApp(notifyevent, ct); + else if (Subscription.DeliveryMethod == NotifyDeliveryMethod.SMTP) + await DeliverSMTP(notifyevent, ct); + + } - // //NORMAL IMMEDIATE DELIVERY EVENT - // if (notifyevent.NotifySubscription.DeliveryMethod == NotifyDeliveryMethod.App) - // { - // await DeliverInApp(notifyevent, ct); - // } - // if (notifyevent.NotifySubscription.DeliveryMethod == NotifyDeliveryMethod.SMTP) - // { - // await DeliverSMTP(notifyevent, ct); - // } - // } } } @@ -230,79 +221,88 @@ namespace AyaNova.Biz private static async Task DeliverInApp(NotifyEvent ne, AyContext ct) { - log.LogTrace($"DeliverInApp deliving notify event: {ne}"); + log.LogTrace($"DeliverInApp notify event: {ne}"); +#if (DEBUG) + log.LogInformation($"DeliverInApp notify event: {ne}"); +#endif await ct.Notification.AddAsync(new Notification() { UserId = ne.UserId, AyaType = ne.AyaType, ObjectId = ne.ObjectId, EventType = ne.EventType, NotifySubscriptionId = ne.NotifySubscriptionId, Message = ne.Message, Name = ne.Name }); + await ct.SaveChangesAsync(); ct.NotifyEvent.Remove(ne); await ct.SaveChangesAsync(); + } private static async Task DeliverSMTP(NotifyEvent ne, AyContext ct) { - log.LogTrace($"DeliverSMTP delivering notify event: {ne}"); - if (string.IsNullOrWhiteSpace(ne.NotifySubscription.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); + await Task.CompletedTask; + throw new NotSupportedException("NEW CACHING CODE NEEDS TO BE ADDED BEFORE SMTP DELIVERIES CAN RESUME TESTING"); + + //TODO: UNCOMMENT THE FOLLOWING AND ADD CACHING AS PER ABOVE + // log.LogTrace($"DeliverSMTP delivering notify event: {ne}"); + // if (string.IsNullOrWhiteSpace(ne.NotifySubscription.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[ne.NotifySubscription.UserId]; - var name = ne.Name; - if (name == "~SERVER~") - name = _ServerTheWordTranslations.First(z => z.Key == transid).Value; + // var transid = _UserTranslationIdCache[ne.NotifySubscription.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)}"; + // //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}"; + // var subject = $"AY{AyaTypeTranslated}:{GetTranslatedNotifyEventName(ne.EventType, transid)}:{name}"; - //subscription link translation - var SubscriptionTypeName = GetTranslatedAyaTypeName(AyaType.NotifySubscription, transid); + // //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)" + // 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) - { - body = OpenObjectUrlBuilder(ne.AyaType, ne.ObjectId, ne.EventType) + "\n"; - } - body += ne.Message; + // 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"; + // //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"; + // 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(ne.NotifySubscription.DeliveryAddress, subject, body, ServerGlobalOpsSettingsCache.Notify); - } - } - catch (Exception ex) - { - await NotifyEventHelper.AddOpsProblemEvent("SMTP Notification failed", ex); - await NotifyEventHelper.AddGeneralNotifyEvent(NotifyEventType.GeneralNotification, $"An error prevented delivering the following notification via email. System operator users have been notified:{ne}", "Error", null, ne.UserId); - } - finally - { - //remove event no matter what - ct.NotifyEvent.Remove(ne); - await ct.SaveChangesAsync(); - } + // 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(ne.NotifySubscription.DeliveryAddress, subject, body, ServerGlobalOpsSettingsCache.Notify); + // } + // } + // catch (Exception ex) + // { + // await NotifyEventHelper.AddOpsProblemEvent("SMTP Notification failed", ex); + // await NotifyEventHelper.AddGeneralNotifyEvent(NotifyEventType.GeneralNotification, $"An error prevented delivering the following notification via email. System operator users have been notified:{ne}", "Error", null, ne.UserId); + // } + // finally + // { + // //remove event no matter what + // ct.NotifyEvent.Remove(ne); + // await ct.SaveChangesAsync(); + // } } //Called from ops notification settings to test smtp setup by delivering to address of choosing diff --git a/server/AyaNova/models/NotifyEvent.cs b/server/AyaNova/models/NotifyEvent.cs index 8691a0ae..5449a835 100644 --- a/server/AyaNova/models/NotifyEvent.cs +++ b/server/AyaNova/models/NotifyEvent.cs @@ -63,8 +63,8 @@ namespace AyaNova.Models } //linked entity - public NotifySubscription NotifySubscription { get; set; } - public User User { get; set; } + // public NotifySubscription NotifySubscription { get; set; } + // public User User { get; set; } }//eoc