From cbab5f21f446cf86cfbc536ef0880227e551c9c6 Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Thu, 24 Dec 2020 23:04:32 +0000 Subject: [PATCH] --- server/AyaNova/biz/NotifyEventHelper.cs | 13 ++++++++++++ server/AyaNova/biz/UserBiz.cs | 13 +++++++++++- server/AyaNova/generator/CoreJobNotify.cs | 24 +++++++++++++++-------- server/AyaNova/models/PM.cs | 6 ++++++ server/AyaNova/models/Quote.cs | 6 ++++++ server/AyaNova/models/WorkOrder.cs | 6 ++++++ 6 files changed, 59 insertions(+), 9 deletions(-) diff --git a/server/AyaNova/biz/NotifyEventHelper.cs b/server/AyaNova/biz/NotifyEventHelper.cs index 096b7f82..d0ae9c03 100644 --- a/server/AyaNova/biz/NotifyEventHelper.cs +++ b/server/AyaNova/biz/NotifyEventHelper.cs @@ -77,6 +77,8 @@ namespace AyaNova.Biz var subs = await ct.NotifySubscription.Where(z => z.EventType == NotifyEventType.ObjectCreated && z.AyaType == newObject.AyaType).ToListAsync(); foreach (var sub in subs) { + //not for inactive users + if (!await UserBiz.UserIsActive(sub.UserId)) continue; if (TagsMatch(newObject.Tags, sub.Tags)) { NotifyEvent n = new NotifyEvent() @@ -101,6 +103,8 @@ namespace AyaNova.Biz var subs = await ct.NotifySubscription.Where(z => z.EventType == NotifyEventType.ObjectAge && z.AyaType == newObject.AyaType).ToListAsync(); foreach (var sub in subs) { + //not for inactive users + if (!await UserBiz.UserIsActive(sub.UserId)) continue; if (TagsMatch(newObject.Tags, sub.Tags)) { //Note: age is set by advance notice which is consulted by CoreJobNotify in it's run so the deliver date is not required here only the reference EventDate to check for deliver @@ -137,6 +141,8 @@ namespace AyaNova.Biz var subs = await ct.NotifySubscription.Where(z => z.EventType == NotifyEventType.ObjectModified && z.AyaType == newObject.AyaType).ToListAsync(); foreach (var sub in subs) { + //not for inactive users + if (!await UserBiz.UserIsActive(sub.UserId)) continue; if (TagsMatch(newObject.Tags, sub.Tags)) { NotifyEvent n = new NotifyEvent() @@ -174,6 +180,8 @@ namespace AyaNova.Biz var subs = await ct.NotifySubscription.Where(z => z.EventType == NotifyEventType.ObjectDeleted && z.AyaType == bizObject.AyaType).ToListAsync(); foreach (var sub in subs) { + //not for inactive users + if (!await UserBiz.UserIsActive(sub.UserId)) continue; if (TagsMatch(bizObject.Tags, sub.Tags)) { //TODO: On deliver should point to history event log record or take from there and insert into delivery message? @@ -265,6 +273,7 @@ namespace AyaNova.Biz internal static async Task AddGeneralNotifyEvent(NotifyEventType eventType, string message, string name, Exception except = null, long userId = 0) { + //This handles general notification events not requiring a decision or tied to an object that are basically just a immediate message to the user //e.g. ops problems, GeneralNotification, NotifyHealthCheck etc //optional user id to send directly to them @@ -301,6 +310,8 @@ namespace AyaNova.Biz //this will likely be a development error, not a production error so no need to log etc throw new System.ArgumentException("NotifyEventProcessor:AddGeneralNotifyEvent: GeneralNotification requires a user id but none was specified"); } + //not for inactive users + if (!await UserBiz.UserIsActive(userId)) return; var UserName = await ct.User.AsNoTracking().Where(z => z.Id == userId).Select(z => z.Name).FirstOrDefaultAsync(); @@ -328,6 +339,8 @@ namespace AyaNova.Biz foreach (var sub in subs) { + //not for inactive users + if (!await UserBiz.UserIsActive(sub.UserId)) continue; //note flag ~SERVER~ means to client to substitute "Server" translation key text instead NotifyEvent n = new NotifyEvent() { EventType = eventType, UserId = sub.UserId, Message = message, NotifySubscriptionId = sub.Id, Name = "~SERVER~" }; await ct.NotifyEvent.AddAsync(n); diff --git a/server/AyaNova/biz/UserBiz.cs b/server/AyaNova/biz/UserBiz.cs index 4e036659..b7d6116b 100644 --- a/server/AyaNova/biz/UserBiz.cs +++ b/server/AyaNova/biz/UserBiz.cs @@ -44,6 +44,16 @@ namespace AyaNova.Biz } } + //check for active status of user + //used by notification processing and others + internal static async Task UserIsActive(long userId) + { + using (AyContext ct = ServiceProviderProvider.DBContext) + { + return await ct.User.AsNoTracking().Where(z => z.Id == userId).Select(z => z.Active).FirstAsync(); + } + } + //Called by license processor when use downgrades to lesser amount of techs internal static async Task DeActivateExcessiveTechs(long KeepThisManyActiveTechs, ILogger _log) { @@ -492,6 +502,7 @@ namespace AyaNova.Biz //USEROPTIONS await ct.Database.ExecuteSqlInterpolatedAsync($"delete from auseroptions where userid = {dbObject.Id}"); //NOTIFY SUBSCRIPTIONS + //Note: will cascade delete notifyevent, and notification automatically await ct.Database.ExecuteSqlInterpolatedAsync($"delete from anotifysubscription where userid = {dbObject.Id}"); //personal datalistview await ct.Database.ExecuteSqlInterpolatedAsync($"delete from adatalistview where public = {false} and userid = {dbObject.Id}"); @@ -942,7 +953,7 @@ namespace AyaNova.Biz //iterate subs and remove any user shouldn't have var userSubs = await ct.NotifySubscription.Where(z => z.UserId == proposedObj.Id).ToListAsync(); foreach (var sub in userSubs) - { + { if (sub.AyaType != AyaType.NoType) { //check if user has rights to it or not still diff --git a/server/AyaNova/generator/CoreJobNotify.cs b/server/AyaNova/generator/CoreJobNotify.cs index b1d0a7e9..b717036a 100644 --- a/server/AyaNova/generator/CoreJobNotify.cs +++ b/server/AyaNova/generator/CoreJobNotify.cs @@ -108,12 +108,12 @@ 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.NotifySubscription).ToListAsync(); + var events = await ct.NotifyEvent.Include(z => z.User).Include(z => z.NotifySubscription).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).Select(z => z.NotifySubscription.UserId).ToList().Distinct(); + 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) { long transId = (await ct.UserOptions.SingleAsync(z => z.UserId == userid)).TranslationId; @@ -126,6 +126,14 @@ namespace AyaNova.Biz //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) + { + log.LogTrace($"Inactive user {notifyevent.User.Name}, removing notify rather than delivering it: {notifyevent}"); + ct.NotifyEvent.Remove(notifyevent); + await ct.SaveChangesAsync(); + continue; + } //TIME DELAYED AGED EVENT? //when to time delay deliver formula:If sub.agevalue!= timespan.zero then deliver on = //NotifyEvent "EventDate"+NotifySubscription.AgeValue timespan - NotifySubscription AdvanceNotice timespan > utcNow @@ -150,7 +158,7 @@ namespace AyaNova.Biz } else { - + //COULD BE TIME DELAYED BUT WITHOUT AGE, i.e. EventDate takes precedence? //NORMAL IMMEDIATE DELIVERY EVENT @@ -249,15 +257,15 @@ namespace AyaNova.Biz if (ne.ObjectId != 0 || ne.EventType == NotifyEventType.BackupStatus) { - body = OpenObjectUrlBuilder(ne.AyaType, ne.ObjectId, ne.EventType) + "\n"; + 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"; - + if (!body.EndsWith('\n')) + body += "\n"; + body += $"-----\n({SubscriptionTypeName}: {OpenSubscriptionUrlBuilder(ne.NotifySubscriptionId)} )\n"; if (!ServerGlobalOpsSettingsCache.Notify.SmtpDeliveryActive) @@ -369,7 +377,7 @@ namespace AyaNova.Biz return "OPS ERROR NO SERVER URL CONFIGURED"; } ServerUrl = ServerUrl.Trim().TrimEnd('/'); - + //default is to open the object in question directly return $"{ServerUrl}/open/{(int)AyaType.NotifySubscription}/{id}"; } diff --git a/server/AyaNova/models/PM.cs b/server/AyaNova/models/PM.cs index e4a04bc0..a1d375e7 100644 --- a/server/AyaNova/models/PM.cs +++ b/server/AyaNova/models/PM.cs @@ -23,7 +23,13 @@ namespace AyaNova.Models public string CustomFields { get; set; } public List Tags { get; set; } +/* +todo: Consider adding latitude / longitude to wo, quote, pm objects + can copy over from the unit or customer or set themselves + and can always hide + means wo could be scheduled for ad-hoc locations and serviced that way, i.e. a truck parked on the side of the highway etc +*/ //dependents public List PMItems { get; set; } diff --git a/server/AyaNova/models/Quote.cs b/server/AyaNova/models/Quote.cs index 7253fb46..ab362ef0 100644 --- a/server/AyaNova/models/Quote.cs +++ b/server/AyaNova/models/Quote.cs @@ -22,7 +22,13 @@ namespace AyaNova.Models public string CustomFields { get; set; } public List Tags { get; set; } +/* +todo: Consider adding latitude / longitude to wo, quote, pm objects + can copy over from the unit or customer or set themselves + and can always hide + means wo could be scheduled for ad-hoc locations and serviced that way, i.e. a truck parked on the side of the highway etc +*/ //dependents public List QuoteItems { get; set; } diff --git a/server/AyaNova/models/WorkOrder.cs b/server/AyaNova/models/WorkOrder.cs index 6c703b52..0c88191b 100644 --- a/server/AyaNova/models/WorkOrder.cs +++ b/server/AyaNova/models/WorkOrder.cs @@ -30,7 +30,13 @@ namespace AyaNova.Models public AyaType AyaType { get => AyaType.WorkOrder; } }//eoc +/* +todo: Consider adding latitude / longitude to wo, quote, pm objects + can copy over from the unit or customer or set themselves + and can always hide + means wo could be scheduled for ad-hoc locations and serviced that way, i.e. a truck parked on the side of the highway etc +*/ public class WorkOrder : ICoreBizObjectModel { public WorkOrder()