This commit is contained in:
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@@ -48,7 +48,7 @@
|
||||
"AYANOVA_DATA_PATH": "c:\\temp\\ravendata",
|
||||
"AYANOVA_USE_URLS": "http://*:7575;",
|
||||
//"AYANOVA_PERMANENTLY_ERASE_DATABASE":"true",
|
||||
"AYANOVA_SERVER_TEST_MODE": "false",
|
||||
"AYANOVA_SERVER_TEST_MODE": "true",
|
||||
"AYANOVA_SERVER_TEST_MODE_TZ_OFFSET": "-8",
|
||||
//"AYANOVA_REPORT_RENDERING_TIMEOUT":"1",
|
||||
"AYANOVA_SERVER_TEST_MODE_SEEDLEVEL": "small",
|
||||
|
||||
@@ -1293,6 +1293,7 @@ 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,
|
||||
@@ -1300,7 +1301,8 @@ namespace AyaNova.Biz
|
||||
AyaType = AyaType.Quote,
|
||||
ObjectId = oProposed.QuoteId,
|
||||
CustomerNotifySubscriptionId = sub.Id,
|
||||
Name = $"{QuoteInfo.Serial.ToString()} - {qos.Name}"
|
||||
Name = $"{QuoteInfo.Serial.ToString()} - {qos.Name}",
|
||||
Message=//TODO: template processing here
|
||||
};
|
||||
await ct.CustomerNotifyEvent.AddAsync(n);
|
||||
log.LogDebug($"Adding CustomerNotifyEvent: [{n.ToString()}]");
|
||||
|
||||
@@ -133,13 +133,13 @@ namespace AyaNova.Biz
|
||||
if (Subscription.DeliveryMethod == NotifyDeliveryMethod.App)
|
||||
await DeliverInApp(notifyevent, Subscription.AgeValue, ct);
|
||||
else if (Subscription.DeliveryMethod == NotifyDeliveryMethod.SMTP)
|
||||
await DeliverSMTP(notifyevent, Subscription.AgeValue, Subscription.AdvanceNotice, Subscription.DeliveryAddress, ct);
|
||||
await DeliverUserNotificationSMTP(notifyevent, Subscription.AgeValue, Subscription.AdvanceNotice, Subscription.DeliveryAddress, ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion user notification events
|
||||
|
||||
|
||||
|
||||
|
||||
#region Customer 'proxy' notification subscription events
|
||||
using (AyContext ct = AyaNova.Util.ServiceProviderProvider.DBContext)
|
||||
{
|
||||
@@ -150,8 +150,8 @@ namespace AyaNova.Biz
|
||||
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();
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -161,7 +161,7 @@ namespace AyaNova.Biz
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(CustInfo.EmailAddress))
|
||||
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);
|
||||
@@ -170,7 +170,7 @@ namespace AyaNova.Biz
|
||||
}
|
||||
|
||||
//Get subscription for delivery
|
||||
var Subscription = await ct.NotifySubscription.AsNoTracking().FirstOrDefaultAsync(x => x.Id == customernotifyevent.NotifySubscriptionId);
|
||||
var Subscription = await ct.CustomerNotifySubscription.AsNoTracking().FirstOrDefaultAsync(x => x.Id == customernotifyevent.CustomerNotifySubscriptionId);
|
||||
|
||||
//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
|
||||
@@ -180,48 +180,13 @@ namespace AyaNova.Biz
|
||||
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);
|
||||
await DeliverCustomerNotificationSMTP(customernotifyevent, Subscription, CustInfo.EmailAddress, ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion customer notification events
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -270,7 +235,7 @@ namespace AyaNova.Biz
|
||||
|
||||
|
||||
|
||||
private static async Task DeliverSMTP(NotifyEvent ne, TimeSpan ageValue, TimeSpan advanceNotice, string deliveryAddress, AyContext ct)
|
||||
private static async Task DeliverUserNotificationSMTP(NotifyEvent ne, TimeSpan ageValue, TimeSpan advanceNotice, string deliveryAddress, AyContext ct)
|
||||
{
|
||||
var DeliveryLogItem = new NotifyDeliveryLog()
|
||||
{
|
||||
@@ -414,6 +379,97 @@ namespace AyaNova.Biz
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//===
|
||||
private static async Task DeliverCustomerNotificationSMTP(CustomerNotifyEvent ne, CustomerNotifySubscription subscription, string deliveryAddress, AyContext ct)
|
||||
{
|
||||
|
||||
var DeliveryLogItem = new NotifyDeliveryLog()
|
||||
{
|
||||
Processed = DateTime.UtcNow,
|
||||
ObjectId = ne.ObjectId,
|
||||
NotifySubscriptionId = ne.CustomerNotifySubscriptionId,
|
||||
Fail = false
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
log.LogDebug($"DeliverCustomerNotificationSMTP delivering notify event: {ne}");
|
||||
if (string.IsNullOrWhiteSpace(deliveryAddress))
|
||||
{
|
||||
DeliveryLogItem.Fail = true;
|
||||
DeliveryLogItem.Error = $"No email address provided for smtp delivery; event: {ne}";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
string subject = "";
|
||||
|
||||
|
||||
IMailer m = AyaNova.Util.ServiceProviderProvider.Mailer;
|
||||
var body = "";
|
||||
|
||||
//Special notification handling
|
||||
switch (ne.EventType)
|
||||
{
|
||||
case NotifyEventType.CustomerServiceImminent:
|
||||
subject = subscription.;
|
||||
body = LT["NotifyEventCustomerServiceImminentMessage"].Replace("{0}", AyaNova.Util.DateUtil.FormatTimeSpan(advanceNotice, LT["TimeSpanDays"], LT["TimeSpanHours"], LT["TimeSpanMinutes"], LT["TimeSpanSeconds"]));
|
||||
body += $"\n{OpenObjectUrlBuilder(ne.AyaType, ne.ObjectId, ne.EventType)}\n";
|
||||
break;
|
||||
default:
|
||||
subject = $"AY:{AyaTypeTranslated}:{name}:{SubscriptionTypeName}";
|
||||
if (ne.ObjectId != 0 || ne.EventType == NotifyEventType.BackupStatus)
|
||||
{
|
||||
body = $"{AgeDisplay}{DecDisplay}{AyaTypeTranslated}\n{OpenObjectUrlBuilder(ne.AyaType, ne.ObjectId, ne.EventType)}\n";
|
||||
}
|
||||
body += ne.Message;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//Add link to subscription, all messages have this regardless of content
|
||||
//http://localhost:8080/open/51/1 //add subscription link, notifysub is object type 51
|
||||
if (!body.EndsWith('\n'))
|
||||
body += "\n";
|
||||
|
||||
body += $"-----\n{NotifySubscriptionLinkText}\n{OpenSubscriptionUrlBuilder(ne.CustomerNotifySubscriptionId)}\n";
|
||||
|
||||
if (!ServerGlobalOpsSettingsCache.Notify.SmtpDeliveryActive)
|
||||
{
|
||||
await NotifyEventHelper.AddOpsProblemEvent($"Email notifications are set to OFF at server, unable to send Customer email notification for this event:{ne}");
|
||||
log.LogInformation($"** WARNING: SMTP notification is currently set to Active=False; unable to deliver Customer email notification, [CustomerId={ne.CustomerId}, Customer Notify subscription={ne.CustomerNotifySubscriptionId}]. Change this setting or remove all Customer notifications if this is permanent **");
|
||||
DeliveryLogItem.Fail = true;
|
||||
DeliveryLogItem.Error = $"Email notifications are set to OFF at server, unable to send Customer email notification for this event: {ne}";
|
||||
}
|
||||
else
|
||||
await m.SendEmailAsync(deliveryAddress, subject, body, ServerGlobalOpsSettingsCache.Notify);
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await NotifyEventHelper.AddOpsProblemEvent("SMTP Customer Notification failed", ex);
|
||||
DeliveryLogItem.Fail = true;
|
||||
DeliveryLogItem.Error = $"SMTP Notification failed to deliver for this Customer notify event: {ne}, message: {ex.Message}";
|
||||
log.LogDebug(ex, $"DeliverSMTP Failure delivering Customer notify event: {ne}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
//remove event no matter what
|
||||
ct.CustomerNotifyEvent.Remove(ne);
|
||||
|
||||
//add delivery log item
|
||||
await ct.NotifyDeliveryLog.AddAsync(DeliveryLogItem);
|
||||
await ct.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
//===
|
||||
|
||||
|
||||
//Called from ops notification settings to test smtp setup by delivering to address of choosing
|
||||
public static async Task<string> TestSMTPDelivery(string toAddress)
|
||||
{
|
||||
|
||||
@@ -24,12 +24,14 @@ namespace AyaNova.Models
|
||||
public long CustomerId { get; set; }
|
||||
[Required]
|
||||
public long CustomerNotifySubscriptionId { get; set; }//source subscription that triggered this event to be created
|
||||
|
||||
|
||||
public decimal DecValue { get; set; }
|
||||
|
||||
//date of the event actually occuring, e.g. WarrantyExpiry date. Compared with subscription to determine if deliverable or not
|
||||
public DateTime EventDate { get; set; }
|
||||
public string Message { get; set; }
|
||||
public string Subject { get; set; }//email subject line
|
||||
public string Message { get; set; }//email body
|
||||
|
||||
|
||||
|
||||
public CustomerNotifyEvent()
|
||||
@@ -48,8 +50,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
|
||||
|
||||
|
||||
@@ -38,6 +38,10 @@ namespace AyaNova.Models
|
||||
public List<string> Tags { get; set; }//Tags to filter an event, object *must* have these tags to generate event related to it (AT TIME OF UPDATE)
|
||||
[Required]
|
||||
public string Template { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Subject { get; set; }
|
||||
|
||||
|
||||
//DELIVERY CONDITIONS - following are all conditions on *whether* to deliver the existing notify event or not
|
||||
public TimeSpan AgeValue { get; set; }//for events that depend on an age of something (e.g. WorkorderStatusAge), This value determines when event has "come of age" but advancenotice controls how far in advance of this delivery is made
|
||||
|
||||
@@ -22,9 +22,9 @@ namespace AyaNova.Util
|
||||
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImportingAsync WHEN NEW TABLES ADDED!!!!
|
||||
private const int DESIRED_SCHEMA_LEVEL = 1;
|
||||
|
||||
internal const long EXPECTED_COLUMN_COUNT = 1353;
|
||||
internal const long EXPECTED_COLUMN_COUNT = 1355;
|
||||
internal const long EXPECTED_INDEX_COUNT = 155;
|
||||
internal const long EXPECTED_CHECK_CONSTRAINTS = 542;
|
||||
internal const long EXPECTED_CHECK_CONSTRAINTS = 545;
|
||||
internal const long EXPECTED_FOREIGN_KEY_CONSTRAINTS = 201;
|
||||
internal const long EXPECTED_VIEWS = 11;
|
||||
internal const long EXPECTED_ROUTINES = 2;
|
||||
@@ -1211,11 +1211,11 @@ $BODY$ LANGUAGE PLPGSQL STABLE");
|
||||
+ "currencyname TEXT NOT NULL, hour12 BOOL NOT NULL, "
|
||||
+ "customertags VARCHAR(255) ARRAY, ayatype INTEGER NOT NULL, eventtype INTEGER NOT NULL, advancenotice INTERVAL NOT NULL, "
|
||||
+ "idvalue BIGINT NOT NULL, decvalue DECIMAL(38,18) NOT NULL, agevalue INTERVAL NOT NULL, "
|
||||
+ "linkreportid BIGINT, template TEXT NOT NULL, tags VARCHAR(255) ARRAY)");
|
||||
+ "linkreportid BIGINT, template TEXT NOT NULL, subject TEXT NOT NULL, tags VARCHAR(255) ARRAY)");
|
||||
|
||||
await ExecQueryAsync("CREATE TABLE acustomernotifyevent (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, created TIMESTAMPTZ NOT NULL, "
|
||||
+ "ayatype INTEGER NOT NULL, objectid BIGINT NOT NULL, name TEXT NOT NULL, eventtype INTEGER NOT NULL, customernotifysubscriptionid BIGINT NOT NULL REFERENCES acustomernotifysubscription(id) ON DELETE CASCADE, "
|
||||
+ "customerid BIGINT NOT NULL REFERENCES acustomer (id) ON DELETE CASCADE, eventdate TIMESTAMPTZ NOT NULL, decvalue DECIMAL(38,18) NULL, message TEXT)");
|
||||
+ "customerid BIGINT NOT NULL REFERENCES acustomer (id) ON DELETE CASCADE, eventdate TIMESTAMPTZ NOT NULL, decvalue DECIMAL(38,18) NULL, message TEXT NOT NULL, subject TEXT NOT NULL,)");
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user