This commit is contained in:
2022-03-07 20:50:19 +00:00
parent 161986c246
commit b4f5ef3a72
6 changed files with 119 additions and 55 deletions

2
.vscode/launch.json vendored
View File

@@ -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",

View File

@@ -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()}]");

View File

@@ -133,7 +133,7 @@ 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);
}
}
}
@@ -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,43 +180,8 @@ 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);
}
}
}
@@ -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)
{

View File

@@ -29,7 +29,9 @@ namespace AyaNova.Models
//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()

View File

@@ -39,6 +39,10 @@ namespace AyaNova.Models
[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

View File

@@ -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,)");