This commit is contained in:
@@ -202,21 +202,11 @@ namespace Sockeye.Biz
|
|||||||
|
|
||||||
private async Task ValidateAsync(GZCase proposedObj, GZCase currentObj)
|
private async Task ValidateAsync(GZCase proposedObj, GZCase currentObj)
|
||||||
{
|
{
|
||||||
bool isNew = currentObj == null;
|
await Task.CompletedTask;
|
||||||
|
// bool isNew = currentObj == null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Any form customizations to validate?
|
|
||||||
var FormCustomization = await ct.FormCustom.AsNoTracking().SingleOrDefaultAsync(z => z.FormKey == SockType.GZCase.ToString());
|
|
||||||
if (FormCustomization != null)
|
|
||||||
{
|
|
||||||
//Yeppers, do the validation, there are two, the custom fields and the regular fields that might be set to required
|
|
||||||
|
|
||||||
//validate users choices for required non custom fields
|
|
||||||
RequiredFieldsValidator.Validate(this, FormCustomization, proposedObj);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -240,24 +240,7 @@ namespace Sockeye.Biz
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static string GenFetchCode()
|
|
||||||
{
|
|
||||||
|
|
||||||
//sufficient for this purpose
|
|
||||||
//https://stackoverflow.com/a/1344258/8939
|
|
||||||
|
|
||||||
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
||||||
var stringChars = new char[10];
|
|
||||||
var random = new Random();
|
|
||||||
|
|
||||||
for (int i = 0; i < stringChars.Length; i++)
|
|
||||||
{
|
|
||||||
stringChars[i] = chars[random.Next(chars.Length)];
|
|
||||||
}
|
|
||||||
|
|
||||||
var finalString = new String(stringChars);
|
|
||||||
return finalString;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static Dictionary<string, DateTime> LicenseToPluginsArray(License l)
|
private static Dictionary<string, DateTime> LicenseToPluginsArray(License l)
|
||||||
@@ -309,7 +292,7 @@ namespace Sockeye.Biz
|
|||||||
|
|
||||||
StringBuilder sbKey = new StringBuilder();
|
StringBuilder sbKey = new StringBuilder();
|
||||||
StringWriter sw = new StringWriter(sbKey);
|
StringWriter sw = new StringWriter(sbKey);
|
||||||
l.FetchCode = GenFetchCode();
|
l.FetchCode = StringUtil.GenFetchCode();
|
||||||
using (Newtonsoft.Json.JsonWriter w = new Newtonsoft.Json.JsonTextWriter(sw))
|
using (Newtonsoft.Json.JsonWriter w = new Newtonsoft.Json.JsonTextWriter(sw))
|
||||||
{
|
{
|
||||||
w.Formatting = Newtonsoft.Json.Formatting.Indented;
|
w.Formatting = Newtonsoft.Json.Formatting.Indented;
|
||||||
|
|||||||
@@ -500,6 +500,12 @@ namespace Sockeye.Biz
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await ct.SaveChangesAsync();
|
await ct.SaveChangesAsync();
|
||||||
|
|
||||||
|
//TODO: NOTIFICATION ON NEW KEY
|
||||||
|
//BUT NOT if REVOKED token is the regto, we don't want them to know, just let AyaNova install it
|
||||||
|
//this is for non-payment scenarios or chargebacks after license was sent
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (DbUpdateConcurrencyException)
|
catch (DbUpdateConcurrencyException)
|
||||||
{
|
{
|
||||||
@@ -761,19 +767,7 @@ namespace Sockeye.Biz
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await Task.CompletedTask;
|
||||||
|
|
||||||
//Any form customizations to validate?
|
|
||||||
var FormCustomization = await ct.FormCustom.AsNoTracking().SingleOrDefaultAsync(z => z.FormKey == SockType.License.ToString());
|
|
||||||
if (FormCustomization != null)
|
|
||||||
{
|
|
||||||
//Yeppers, do the validation, there are two, the custom fields and the regular fields that might be set to required
|
|
||||||
|
|
||||||
//validate users choices for required non custom fields
|
|
||||||
RequiredFieldsValidator.Validate(this, FormCustomization, proposedObj);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -202,20 +202,7 @@ namespace Sockeye.Biz
|
|||||||
|
|
||||||
private async Task ValidateAsync(Product proposedObj, Product currentObj)
|
private async Task ValidateAsync(Product proposedObj, Product currentObj)
|
||||||
{
|
{
|
||||||
bool isNew = currentObj == null;
|
await Task.CompletedTask;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Any form customizations to validate?
|
|
||||||
var FormCustomization = await ct.FormCustom.AsNoTracking().SingleOrDefaultAsync(z => z.FormKey == SockType.Product.ToString());
|
|
||||||
if (FormCustomization != null)
|
|
||||||
{
|
|
||||||
//Yeppers, do the validation, there are two, the custom fields and the regular fields that might be set to required
|
|
||||||
|
|
||||||
//validate users choices for required non custom fields
|
|
||||||
RequiredFieldsValidator.Validate(this, FormCustomization, proposedObj);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -203,20 +203,7 @@ namespace Sockeye.Biz
|
|||||||
|
|
||||||
private async Task ValidateAsync(Purchase proposedObj, Purchase currentObj)
|
private async Task ValidateAsync(Purchase proposedObj, Purchase currentObj)
|
||||||
{
|
{
|
||||||
bool isNew = currentObj == null;
|
await Task.CompletedTask;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Any form customizations to validate?
|
|
||||||
var FormCustomization = await ct.FormCustom.AsNoTracking().SingleOrDefaultAsync(z => z.FormKey == SockType.Purchase.ToString());
|
|
||||||
if (FormCustomization != null)
|
|
||||||
{
|
|
||||||
//Yeppers, do the validation, there are two, the custom fields and the regular fields that might be set to required
|
|
||||||
|
|
||||||
//validate users choices for required non custom fields
|
|
||||||
RequiredFieldsValidator.Validate(this, FormCustomization, proposedObj);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,10 +16,12 @@ namespace Sockeye.Biz
|
|||||||
//Key generator controller
|
//Key generator controller
|
||||||
public static class RavenKeyFactory
|
public static class RavenKeyFactory
|
||||||
{
|
{
|
||||||
//Sept 2022 decided all trial periods are 7 days, they can keep renewing a new trial by erasing data or request a longer period case by case
|
//Jan 2023 values
|
||||||
public const int TRIAL_PERIOD_DAYS = 7;
|
public const int TRIAL_KEY_SUBSCRIPTION_PERIOD_DAYS = 7;
|
||||||
|
public const int TRIAL_KEY_SUBSCRIPTION_CUSTOMER_USERS = 25555;//SEEDING required
|
||||||
|
public const int TRIAL_KEY_SUBSCRIPTION_MAX_DATA_GB = 20;
|
||||||
|
public const int TRIAL_KEY_PERPETUAL_PERIOD_DAYS = 14;
|
||||||
|
public const int TRIAL_KEY_USERS = 5000;//SEEDING required minimum
|
||||||
|
|
||||||
//Unlicensed token
|
//Unlicensed token
|
||||||
private const string UNLICENSED_TOKEN = "UNLICENSED";
|
private const string UNLICENSED_TOKEN = "UNLICENSED";
|
||||||
@@ -29,8 +31,6 @@ namespace Sockeye.Biz
|
|||||||
|
|
||||||
//LICENSE USER COUNT FEATURES
|
//LICENSE USER COUNT FEATURES
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//SUBSCRIPTION
|
//SUBSCRIPTION
|
||||||
private const string ACTIVE_INTERNAL_USERS_FEATURE_NAME = "ActiveInternalUsers";
|
private const string ACTIVE_INTERNAL_USERS_FEATURE_NAME = "ActiveInternalUsers";
|
||||||
private const string ACTIVE_CUSTOMER_USERS_FEATURE_NAME = "ActiveCustomerUsers";
|
private const string ACTIVE_CUSTOMER_USERS_FEATURE_NAME = "ActiveCustomerUsers";
|
||||||
|
|||||||
@@ -208,20 +208,7 @@ namespace Sockeye.Biz
|
|||||||
|
|
||||||
private async Task ValidateAsync(SubscriptionServer proposedObj, SubscriptionServer currentObj)
|
private async Task ValidateAsync(SubscriptionServer proposedObj, SubscriptionServer currentObj)
|
||||||
{
|
{
|
||||||
bool isNew = currentObj == null;
|
await Task.CompletedTask;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Any form customizations to validate?
|
|
||||||
var FormCustomization = await ct.FormCustom.AsNoTracking().SingleOrDefaultAsync(z => z.FormKey == SockType.SubscriptionServer.ToString());
|
|
||||||
if (FormCustomization != null)
|
|
||||||
{
|
|
||||||
//Yeppers, do the validation, there are two, the custom fields and the regular fields that might be set to required
|
|
||||||
|
|
||||||
//validate users choices for required non custom fields
|
|
||||||
RequiredFieldsValidator.Validate(this, FormCustomization, proposedObj);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,11 +49,50 @@ namespace Sockeye.Biz
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
newObject.Tags = TagBiz.NormalizeTags(newObject.Tags);
|
newObject.Tags = TagBiz.NormalizeTags(newObject.Tags);
|
||||||
|
|
||||||
|
//Process a new request / Generate an email confirm code
|
||||||
|
newObject.EmailConfirmCode = StringUtil.GenFetchCode();
|
||||||
|
newObject.EmailValidated = false;
|
||||||
|
newObject.Status = TrialRequestStatus.AwaitingEmailValidation;
|
||||||
|
|
||||||
await ct.TrialLicenseRequest.AddAsync(newObject);
|
await ct.TrialLicenseRequest.AddAsync(newObject);
|
||||||
await ct.SaveChangesAsync();
|
await ct.SaveChangesAsync();
|
||||||
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, newObject.Id, BizType, SockEvent.Created), ct);
|
await EventLogProcessor.LogEventToDatabaseAsync(new Event(1, newObject.Id, BizType, SockEvent.Created), ct);
|
||||||
await SearchIndexAsync(newObject, true);
|
await SearchIndexAsync(newObject, true);
|
||||||
await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, newObject.Tags, null);
|
await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, newObject.Tags, null);
|
||||||
|
|
||||||
|
|
||||||
|
//## ------------------ DEFAULT NOTIFICATIONS TO CUSTOMER ----------------
|
||||||
|
//ValidateEmail request message,RavenTrialApproved (which sends pending manual generation message) and RavenTrialRejected messages are sent in this block
|
||||||
|
//
|
||||||
|
//Send verification request
|
||||||
|
var verifyUrl = ServerGlobalOpsSettingsCache.Notify.SockeyeServerURL.Trim().TrimEnd('/') + $"/trial-license-request/verify/{newObject.EmailConfirmCode}";
|
||||||
|
var body = ServerGlobalBizSettings.Cache.ValidateEmail.Replace("{verifyUrl}", verifyUrl);//$"Please verify your email address by clicking the link below or copy and pasting into a browser\r\n{verifyUrl}\r\nOnce your email is verified the request will be processed manually during business hours.\r\n(If you did not request this you can ignore this message)";
|
||||||
|
|
||||||
|
var notifyDirectSMTP = new Sockeye.Api.Controllers.NotifyController.NotifyDirectSMTP()
|
||||||
|
{
|
||||||
|
ToAddress = newObject.Email,
|
||||||
|
Subject = "AyaNova trial request email verification",
|
||||||
|
TextBody = body
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
IMailer m = Sockeye.Util.ServiceProviderProvider.Mailer;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await m.SendEmailAsync(notifyDirectSMTP.ToAddress, notifyDirectSMTP.Subject, notifyDirectSMTP.TextBody, ServerGlobalOpsSettingsCache.Notify, null, null, null);
|
||||||
|
await EventLogProcessor.LogEventToDatabaseAsync(new Event(1, notifyDirectSMTP.ObjectId, notifyDirectSMTP.SockType, SockEvent.DirectSMTP, $"\"{notifyDirectSMTP.Subject}\"->{notifyDirectSMTP.ToAddress}"), ct);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var err = "TrialLicenseRequest sending email confirmation request: SMTP direct message failed";
|
||||||
|
await NotifyEventHelper.AddOpsProblemEvent(err, ex);
|
||||||
|
AddError(ApiErrorCode.API_SERVER_ERROR, null, ExceptionUtil.ExtractAllExceptionMessages(ex));
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
await HandlePotentialNotificationEvent(SockEvent.Created, newObject);
|
await HandlePotentialNotificationEvent(SockEvent.Created, newObject);
|
||||||
return newObject;
|
return newObject;
|
||||||
}
|
}
|
||||||
@@ -92,10 +131,58 @@ namespace Sockeye.Biz
|
|||||||
putObject.Tags = TagBiz.NormalizeTags(putObject.Tags);
|
putObject.Tags = TagBiz.NormalizeTags(putObject.Tags);
|
||||||
await ValidateAsync(putObject, dbObject);
|
await ValidateAsync(putObject, dbObject);
|
||||||
if (HasErrors) return null;
|
if (HasErrors) return null;
|
||||||
|
|
||||||
|
|
||||||
|
//Automated processint
|
||||||
|
//## ------------------ DEFAULT NOTIFICATIONS TO CUSTOMER ----------------
|
||||||
|
//RavenTrialApproved (which sends pending manual generation message) and RavenTrialRejected messages are sent in this block
|
||||||
|
Sockeye.Api.Controllers.NotifyController.NotifyDirectSMTP notifyDirectSMTP = null;
|
||||||
|
if (dbObject.Status == TrialRequestStatus.AwaitingApproval && putObject.Status == TrialRequestStatus.Approved)
|
||||||
|
{
|
||||||
|
//APPROVED, generate and save key to be approved for release by us
|
||||||
|
putObject.Processed = DateTime.UtcNow;
|
||||||
|
License l = new License();
|
||||||
|
l.Active = false;//not released to customer until we set to active and save
|
||||||
|
l.DbId = putObject.DbId;
|
||||||
|
l.PGroup = putObject.PGroup;
|
||||||
|
l.TrialMode = true;
|
||||||
|
l.RegTo = putObject.CompanyName;
|
||||||
|
//perpet and sub both same number of users, covers seeded data values
|
||||||
|
l.Users = RavenKeyFactory.TRIAL_KEY_USERS;
|
||||||
|
|
||||||
|
if (putObject.PGroup == ProductGroup.RavenPerpetual)
|
||||||
|
{
|
||||||
|
l.LicenseExpire = l.MaintenanceExpire = DateTime.UtcNow.AddDays(RavenKeyFactory.TRIAL_KEY_PERPETUAL_PERIOD_DAYS);
|
||||||
|
}
|
||||||
|
if (putObject.PGroup == ProductGroup.RavenSubscription)
|
||||||
|
{
|
||||||
|
l.LicenseExpire = l.MaintenanceExpire = DateTime.UtcNow.AddDays(RavenKeyFactory.TRIAL_KEY_SUBSCRIPTION_PERIOD_DAYS);
|
||||||
|
l.CustomerUsers = RavenKeyFactory.TRIAL_KEY_SUBSCRIPTION_CUSTOMER_USERS;
|
||||||
|
l.MaxDataGB = RavenKeyFactory.TRIAL_KEY_SUBSCRIPTION_MAX_DATA_GB;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dbObject.Status == TrialRequestStatus.AwaitingApproval && putObject.Status == TrialRequestStatus.Rejected)
|
||||||
|
{
|
||||||
|
//REJECTED, send email
|
||||||
|
putObject.Processed = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ct.Replace(dbObject, putObject);
|
ct.Replace(dbObject, putObject);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await ct.SaveChangesAsync();
|
await ct.SaveChangesAsync();
|
||||||
|
|
||||||
|
//EMAIL?
|
||||||
|
if (notifyDirectSMTP != null)
|
||||||
|
{
|
||||||
|
//send an email
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (DbUpdateConcurrencyException)
|
catch (DbUpdateConcurrencyException)
|
||||||
{
|
{
|
||||||
@@ -204,20 +291,12 @@ namespace Sockeye.Biz
|
|||||||
|
|
||||||
private async Task ValidateAsync(TrialLicenseRequest proposedObj, TrialLicenseRequest currentObj)
|
private async Task ValidateAsync(TrialLicenseRequest proposedObj, TrialLicenseRequest currentObj)
|
||||||
{
|
{
|
||||||
bool isNew = currentObj == null;
|
await Task.CompletedTask;
|
||||||
|
// bool isNew = currentObj == null;
|
||||||
|
|
||||||
|
|
||||||
|
//no need to validate required fields, they are set to required in the model with an attribute
|
||||||
|
|
||||||
//Any form customizations to validate?
|
|
||||||
var FormCustomization = await ct.FormCustom.AsNoTracking().SingleOrDefaultAsync(z => z.FormKey == SockType.TrialLicenseRequest.ToString());
|
|
||||||
if (FormCustomization != null)
|
|
||||||
{
|
|
||||||
//Yeppers, do the validation, there are two, the custom fields and the regular fields that might be set to required
|
|
||||||
|
|
||||||
//validate users choices for required non custom fields
|
|
||||||
RequiredFieldsValidator.Validate(this, FormCustomization, proposedObj);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,103 +528,101 @@ namespace Sockeye.Biz
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
//## ------------------ DEFAULT NOTIFICATIONS ----------------
|
|
||||||
//ValidateEmail request message,RavenTrialApproved (which sends pending manual generation message) and RavenTrialRejected messages are sent in this block
|
|
||||||
//
|
|
||||||
//
|
|
||||||
var custInfo = await ct.Customer.AsNoTracking().Where(x => x.Id == o.CustomerId).Select(x => new { x.Active, x.Tags, x.EmailAddress }).FirstOrDefaultAsync();
|
|
||||||
if (custInfo != null && custInfo.Active && !string.IsNullOrWhiteSpace(custInfo.EmailAddress))//can this customer receive *any* customer notifications?
|
|
||||||
{
|
|
||||||
//-------- Customer is notifiable ------
|
|
||||||
|
|
||||||
// //# STATUS CHANGE (create new status)
|
// todo: maybe this should be a direct smtp message, not bother with the notification system at all as that's how it was done in rockfish and it's kind of orthogonal
|
||||||
|
|
||||||
|
// if ( == !string.IsNullOrWhiteSpace(o.Email))//can this customer receive *any* customer notifications?
|
||||||
// {
|
// {
|
||||||
// //Conditions: must match specific status id value and also tags below
|
// //-------- Customer is notifiable ------
|
||||||
// //delivery is immediate so no need to remove old ones of this kind
|
|
||||||
// var subs = await ct.CustomerNotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderStatusChange && z.IdValue == oProposed.WorkOrderStatusId).OrderBy(z => z.Id).ToListAsync();
|
// // //# STATUS CHANGE (create new status)
|
||||||
// foreach (var sub in subs)
|
// // {
|
||||||
// {
|
// // //Conditions: must match specific status id value and also tags below
|
||||||
// //Object tags must match and Customer tags must match
|
// // //delivery is immediate so no need to remove old ones of this kind
|
||||||
// if (NotifyEventHelper.ObjectHasAllSubscriptionTags(WorkorderInfo.Tags, sub.Tags) && NotifyEventHelper.ObjectHasAllSubscriptionTags(custInfo.Tags, sub.CustomerTags))
|
// // var subs = await ct.CustomerNotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderStatusChange && z.IdValue == oProposed.WorkOrderStatusId).OrderBy(z => z.Id).ToListAsync();
|
||||||
// {
|
// // foreach (var sub in subs)
|
||||||
// CustomerNotifyEvent n = new CustomerNotifyEvent()
|
// // {
|
||||||
// {
|
// // //Object tags must match and Customer tags must match
|
||||||
// EventType = NotifyEventType.WorkorderStatusChange,
|
// // if (NotifyEventHelper.ObjectHasAllSubscriptionTags(WorkorderInfo.Tags, sub.Tags) && NotifyEventHelper.ObjectHasAllSubscriptionTags(custInfo.Tags, sub.CustomerTags))
|
||||||
// CustomerId = WorkorderInfo.CustomerId,
|
// // {
|
||||||
// AyaType = AyaType.WorkOrder,
|
// // CustomerNotifyEvent n = new CustomerNotifyEvent()
|
||||||
// ObjectId = oProposed.WorkOrderId,
|
// // {
|
||||||
// CustomerNotifySubscriptionId = sub.Id,
|
// // EventType = NotifyEventType.WorkorderStatusChange,
|
||||||
// Name = WorkorderInfo.Serial.ToString()
|
// // CustomerId = WorkorderInfo.CustomerId,
|
||||||
// };
|
// // AyaType = AyaType.WorkOrder,
|
||||||
// await ct.CustomerNotifyEvent.AddAsync(n);
|
// // ObjectId = oProposed.WorkOrderId,
|
||||||
// log.LogDebug($"Adding CustomerNotifyEvent: [{n.ToString()}]");
|
// // CustomerNotifySubscriptionId = sub.Id,
|
||||||
// await ct.SaveChangesAsync();
|
// // Name = WorkorderInfo.Serial.ToString()
|
||||||
// break;//we have a match no need to process any further subs for this event
|
// // };
|
||||||
// }
|
// // await ct.CustomerNotifyEvent.AddAsync(n);
|
||||||
// }
|
// // log.LogDebug($"Adding CustomerNotifyEvent: [{n.ToString()}]");
|
||||||
// }//workorder status change event
|
// // await ct.SaveChangesAsync();
|
||||||
|
// // break;//we have a match no need to process any further subs for this event
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
// // }//workorder status change event
|
||||||
|
|
||||||
|
|
||||||
// //# STATUS AGE
|
// // //# STATUS AGE
|
||||||
// {
|
// // {
|
||||||
// //WorkorderStatusAge = 24,//* Workorder STATUS unchanged for set time (stuck in state), conditional on: Duration (how long stuck), exact status selected IdValue, Tags. Advance notice can NOT be set
|
// // //WorkorderStatusAge = 24,//* Workorder STATUS unchanged for set time (stuck in state), conditional on: Duration (how long stuck), exact status selected IdValue, Tags. Advance notice can NOT be set
|
||||||
// //Always clear any old ones for this object as they are all irrelevant the moment the state has changed:
|
// // //Always clear any old ones for this object as they are all irrelevant the moment the state has changed:
|
||||||
// await NotifyEventHelper.ClearPriorCustomerNotifyEventsForObject(ct, proposedObj.AyaType, proposedObj.Id, NotifyEventType.WorkorderStatusAge);
|
// // await NotifyEventHelper.ClearPriorCustomerNotifyEventsForObject(ct, proposedObj.AyaType, proposedObj.Id, NotifyEventType.WorkorderStatusAge);
|
||||||
// var subs = await ct.CustomerNotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderStatusAge && z.IdValue == oProposed.WorkOrderStatusId).OrderBy(z => z.Id).ToListAsync();
|
// // var subs = await ct.CustomerNotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderStatusAge && z.IdValue == oProposed.WorkOrderStatusId).OrderBy(z => z.Id).ToListAsync();
|
||||||
// foreach (var sub in subs)
|
// // foreach (var sub in subs)
|
||||||
// {
|
// // {
|
||||||
// //Object tags must match and Customer tags must match
|
// // //Object tags must match and Customer tags must match
|
||||||
// if (NotifyEventHelper.ObjectHasAllSubscriptionTags(WorkorderInfo.Tags, sub.Tags) && NotifyEventHelper.ObjectHasAllSubscriptionTags(custInfo.Tags, sub.CustomerTags))
|
// // if (NotifyEventHelper.ObjectHasAllSubscriptionTags(WorkorderInfo.Tags, sub.Tags) && NotifyEventHelper.ObjectHasAllSubscriptionTags(custInfo.Tags, sub.CustomerTags))
|
||||||
// {
|
// // {
|
||||||
// CustomerNotifyEvent n = new CustomerNotifyEvent()
|
// // CustomerNotifyEvent n = new CustomerNotifyEvent()
|
||||||
// {
|
// // {
|
||||||
// EventType = NotifyEventType.WorkorderStatusAge,
|
// // EventType = NotifyEventType.WorkorderStatusAge,
|
||||||
// CustomerId = WorkorderInfo.CustomerId,
|
// // CustomerId = WorkorderInfo.CustomerId,
|
||||||
// AyaType = AyaType.WorkOrder,
|
// // AyaType = AyaType.WorkOrder,
|
||||||
// ObjectId = oProposed.WorkOrderId,
|
// // ObjectId = oProposed.WorkOrderId,
|
||||||
// CustomerNotifySubscriptionId = sub.Id,
|
// // CustomerNotifySubscriptionId = sub.Id,
|
||||||
// Name = WorkorderInfo.Serial.ToString()
|
// // Name = WorkorderInfo.Serial.ToString()
|
||||||
// };
|
// // };
|
||||||
// await ct.CustomerNotifyEvent.AddAsync(n);
|
// // await ct.CustomerNotifyEvent.AddAsync(n);
|
||||||
// log.LogDebug($"Adding CustomerNotifyEvent: [{n.ToString()}]");
|
// // log.LogDebug($"Adding CustomerNotifyEvent: [{n.ToString()}]");
|
||||||
// await ct.SaveChangesAsync();
|
// // await ct.SaveChangesAsync();
|
||||||
// break;//we have a match no need to process any further subs for this event
|
// // break;//we have a match no need to process any further subs for this event
|
||||||
// }
|
// // }
|
||||||
// }
|
// // }
|
||||||
// }//workorder status age event
|
// // }//workorder status age event
|
||||||
|
|
||||||
|
|
||||||
// //# WorkorderCompleted
|
// // //# WorkorderCompleted
|
||||||
// {
|
// // {
|
||||||
// if (wos.Completed)
|
// // if (wos.Completed)
|
||||||
// {
|
// // {
|
||||||
// var subs = await ct.CustomerNotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderCompleted).OrderBy(z => z.Id).ToListAsync();
|
// // var subs = await ct.CustomerNotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderCompleted).OrderBy(z => z.Id).ToListAsync();
|
||||||
// foreach (var sub in subs)
|
// // foreach (var sub in subs)
|
||||||
// {
|
// // {
|
||||||
// //Object tags must match and Customer tags must match
|
// // //Object tags must match and Customer tags must match
|
||||||
// if (NotifyEventHelper.ObjectHasAllSubscriptionTags(WorkorderInfo.Tags, sub.Tags) && NotifyEventHelper.ObjectHasAllSubscriptionTags(custInfo.Tags, sub.CustomerTags))
|
// // if (NotifyEventHelper.ObjectHasAllSubscriptionTags(WorkorderInfo.Tags, sub.Tags) && NotifyEventHelper.ObjectHasAllSubscriptionTags(custInfo.Tags, sub.CustomerTags))
|
||||||
// {
|
// // {
|
||||||
|
|
||||||
// CustomerNotifyEvent n = new CustomerNotifyEvent()
|
// // CustomerNotifyEvent n = new CustomerNotifyEvent()
|
||||||
// {
|
// // {
|
||||||
// EventType = NotifyEventType.WorkorderCompleted,
|
// // EventType = NotifyEventType.WorkorderCompleted,
|
||||||
// CustomerId = WorkorderInfo.CustomerId,
|
// // CustomerId = WorkorderInfo.CustomerId,
|
||||||
// AyaType = AyaType.WorkOrder,
|
// // AyaType = AyaType.WorkOrder,
|
||||||
// ObjectId = oProposed.WorkOrderId,
|
// // ObjectId = oProposed.WorkOrderId,
|
||||||
// CustomerNotifySubscriptionId = sub.Id,
|
// // CustomerNotifySubscriptionId = sub.Id,
|
||||||
// Name = WorkorderInfo.Serial.ToString()
|
// // Name = WorkorderInfo.Serial.ToString()
|
||||||
// };
|
// // };
|
||||||
// await ct.CustomerNotifyEvent.AddAsync(n);
|
// // await ct.CustomerNotifyEvent.AddAsync(n);
|
||||||
// log.LogDebug($"Adding CustomerNotifyEvent: [{n.ToString()}]");
|
// // log.LogDebug($"Adding CustomerNotifyEvent: [{n.ToString()}]");
|
||||||
// await ct.SaveChangesAsync();
|
// // await ct.SaveChangesAsync();
|
||||||
// break;//we have a match no need to process any further subs for this event
|
// // break;//we have a match no need to process any further subs for this event
|
||||||
// }
|
// // }
|
||||||
// }
|
// // }
|
||||||
// }
|
// // }
|
||||||
// }//WorkorderCompleted
|
// // }//WorkorderCompleted
|
||||||
|
|
||||||
//-----------------------
|
// //-----------------------
|
||||||
} //------------------ /default notifications ---------------
|
// } //------------------ /default notifications ---------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -165,6 +165,30 @@ namespace Sockeye.Util
|
|||||||
return Encoding.ASCII.GetString(bytes); // returns: "Hello world" for "48656C6C6F20776F726C64"
|
return Encoding.ASCII.GetString(bytes); // returns: "Hello world" for "48656C6C6F20776F726C64"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Generate a random code for email validation and v7 license key fetching
|
||||||
|
//doesn't have to be perfect, it's only temporary and
|
||||||
|
//requires knowledge of the customer / trial user
|
||||||
|
//email address to use it so it's kind of 2 factor
|
||||||
|
public static string GenFetchCode()
|
||||||
|
{
|
||||||
|
|
||||||
|
//sufficient for this purpose
|
||||||
|
//https://stackoverflow.com/a/1344258/8939
|
||||||
|
|
||||||
|
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||||
|
var stringChars = new char[10];
|
||||||
|
var random = new Random();
|
||||||
|
|
||||||
|
for (int i = 0; i < stringChars.Length; i++)
|
||||||
|
{
|
||||||
|
stringChars[i] = chars[random.Next(chars.Length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
var finalString = new String(stringChars);
|
||||||
|
return finalString;
|
||||||
|
}
|
||||||
|
|
||||||
}//eoc
|
}//eoc
|
||||||
|
|
||||||
}//eons
|
}//eons
|
||||||
3
todo.txt
3
todo.txt
@@ -1,5 +1,8 @@
|
|||||||
TODO:
|
TODO:
|
||||||
|
|
||||||
|
DOCS
|
||||||
|
Once it's up and running update docs to mention that perpetual trial period is two weeks subscription is one week
|
||||||
|
|
||||||
|
|
||||||
- Purchase event must trigger notification event subscribable (might already due to created etc)
|
- Purchase event must trigger notification event subscribable (might already due to created etc)
|
||||||
- figure out and implement default notifications for Customers where appropriate
|
- figure out and implement default notifications for Customers where appropriate
|
||||||
|
|||||||
Reference in New Issue
Block a user