diff --git a/server/AyaNova/Startup.cs b/server/AyaNova/Startup.cs index 835db233..46eb80b2 100644 --- a/server/AyaNova/Startup.cs +++ b/server/AyaNova/Startup.cs @@ -700,7 +700,7 @@ namespace AyaNova //Log the active user count so it's in the log record - _newLog.LogInformation($"Active techs - {UserBiz.ActiveCountAsync().Result}"); + _newLog.LogInformation($"Active techs - {UserBiz.ActiveTechUserCountAsync().Result}"); //Log the license info so it's on the record _newLog.LogInformation($"License - [{AyaNova.Core.License.LicenseInfoLogFormat}]"); diff --git a/server/AyaNova/biz/UserBiz.cs b/server/AyaNova/biz/UserBiz.cs index 3bba1b6b..1922eafc 100644 --- a/server/AyaNova/biz/UserBiz.cs +++ b/server/AyaNova/biz/UserBiz.cs @@ -26,12 +26,10 @@ namespace AyaNova.Biz } //This is where active tech license consumers are accounted for - internal static async Task ActiveCountAsync() + internal static async Task ActiveTechUserCountAsync() { using (AyContext ct = ServiceProviderProvider.DBContext) { - // var ret = await ct.Database.ExecuteSqlRawAsync($"SELECT COUNT(*) FROM auser AS a WHERE (a.active = TRUE) AND ((a.usertype = 2) OR (a.usertype = 7))"); - var ret = await ct.User.AsNoTracking().Where(z => z.Active == true && ( z.UserType == UserType.Service || z.UserType == UserType.ServiceContractor)).LongCountAsync(); @@ -39,6 +37,30 @@ namespace AyaNova.Biz } } + //This is where SUBSCRIPTION active internal (non customer) license consumers are accounted for + internal static async Task ActiveInsideUserCountAsync() + { + using (AyContext ct = ServiceProviderProvider.DBContext) + { + var ret = await ct.User.AsNoTracking().Where(z => z.Active == true && ( + z.UserType != UserType.Customer && + z.UserType != UserType.HeadOffice)).LongCountAsync(); + return ret; + } + } + + //This is where SUBSCRIPTION active CUSTOMER CONTACT license consumers are accounted for + internal static async Task ActiveCustomerContactUserCountAsync() + { + using (AyContext ct = ServiceProviderProvider.DBContext) + { + var ret = await ct.User.AsNoTracking().Where(z => z.Active == true && ( + z.UserType == UserType.Customer || + z.UserType == UserType.HeadOffice)).LongCountAsync(); + return ret; + } + } + //check for active status of user //used by notification processing and others internal static async Task UserIsActive(long userId) @@ -52,7 +74,7 @@ namespace AyaNova.Biz //Called by license processor when use downgrades to lesser amount of techs internal static async Task DeActivateExcessiveTechs(long KeepThisManyActiveTechs, ILogger _log) { - var TotalActiveTechs = await ActiveCountAsync(); + var TotalActiveTechs = await ActiveTechUserCountAsync(); int CountOfTechsToSetInactive = (int)(TotalActiveTechs - KeepThisManyActiveTechs); if (CountOfTechsToSetInactive < 1) return; _log.LogInformation($"New license is a downgrade with fewer scheduleable resources, deactivating {CountOfTechsToSetInactive} scheduleable users automatically so the license can be installed"); @@ -733,7 +755,7 @@ namespace AyaNova.Biz if (proposedObj.IsTech && proposedObj.Active) { //Yes, it might be affected depending on things - long CurrentActiveCount = await UserBiz.ActiveCountAsync(); + long CurrentActiveCount = await UserBiz.ActiveTechUserCountAsync(); long LicensedUserCount = AyaNova.Core.License.ActiveKey.ActiveNumber; if (isNew) @@ -799,8 +821,8 @@ namespace AyaNova.Biz } - - + + if (!proposedObj.UserType.IsValid()) { AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "UserType"); diff --git a/server/AyaNova/generator/CoreJobSweeper.cs b/server/AyaNova/generator/CoreJobSweeper.cs index 9f950e70..84700731 100644 --- a/server/AyaNova/generator/CoreJobSweeper.cs +++ b/server/AyaNova/generator/CoreJobSweeper.cs @@ -57,7 +57,7 @@ namespace AyaNova.Biz await SweepInternalJobsLogsAsync(ct, dtDeleteCutoff); //Stealthy check of user count exceeded - if (await UserBiz.ActiveCountAsync() > AyaNova.Core.License.ActiveKey.ActiveNumber) + if (await UserBiz.ActiveTechUserCountAsync() > AyaNova.Core.License.ActiveKey.ActiveNumber) { //WARNING: DO not change the text of this message without also //updating the authcontroller ReturnUserCredsOnSuccessfulAuthentication licenselockout check code diff --git a/server/AyaNova/util/License.cs b/server/AyaNova/util/License.cs index b9a90562..1829eb93 100644 --- a/server/AyaNova/util/License.cs +++ b/server/AyaNova/util/License.cs @@ -64,8 +64,11 @@ namespace AyaNova.Core //Scheduleable users private const string SERVICE_TECHS_FEATURE_NAME = "ServiceTechs"; - //Accounting add-on - private const string ACCOUNTING_FEATURE_NAME = "Accounting"; + //ActiveInternalUsers subscription license + private const string ACTIVE_INTERNAL_USERS_FEATURE_NAME = "ActiveInternalUsers"; + + //ActiveCustomerUsers subscription license + private const string ACTIVE_CUSTOMER_USERS_FEATURE_NAME = "ActiveCustomerUsers"; //This feature name means it's a trial key private const string TRIAL_FEATURE_NAME = "TrialMode"; @@ -756,7 +759,7 @@ namespace AyaNova.Core } //Has someone been trying funny business with the active techs in the db? - if (await AyaNova.Biz.UserBiz.ActiveCountAsync() > _ActiveLicense.ActiveNumber) + if (await AyaNova.Biz.UserBiz.ActiveTechUserCountAsync() > _ActiveLicense.ActiveNumber) { var msg = $"E1020 - Active count exceeded capacity"; apiServerState.SetSystemLock(msg); @@ -805,16 +808,46 @@ namespace AyaNova.Core throw new ApplicationException("E1020 - Can't install a trial key into a non empty AyaNova database. Erase the database first."); } - //TECHCOUNT - new license causes exceeding count? +#if (SUBSCRIPTION_BUILD) + + //SUBSCRIPTION USER COUNTS - new license causes exceeding counts? + + long NewInsideUserLicensedCount = ParsedNewKey.GetLicenseFeature(ACTIVE_INTERNAL_USERS_FEATURE_NAME).Count; + long ExistingActiveInsideUserCount = await AyaNova.Biz.UserBiz.ActiveInsideUserCountAsync(); + + long NewCustomerLicensedCount = ParsedNewKey.GetLicenseFeature(ACTIVE_CUSTOMER_USERS_FEATURE_NAME).Count; + long ExistingCustomerUserCount = await AyaNova.Biz.UserBiz.ActiveCustomerContactUserCountAsync(); + string err = "E1020 - Can't install license: "; + bool throwit = false; + if (ExistingActiveInsideUserCount > NewInsideUserLicensedCount) + { + throwit = true; + err += $"{ExistingActiveInsideUserCount} active internal users of {NewInsideUserLicensedCount} permitted"; + } + + if (ExistingCustomerUserCount > NewCustomerLicensedCount) + { + throwit = true; + err += $"{ExistingCustomerUserCount} active Customer login users of {NewCustomerLicensedCount} permitted"; + } + + if (throwit) + throw new ApplicationException(err); + +#else + //PERPETUAL, vet the TECHCOUNT - new license causes exceeding count? long NewTechCount = ParsedNewKey.GetLicenseFeature(SERVICE_TECHS_FEATURE_NAME).Count; - if (await AyaNova.Biz.UserBiz.ActiveCountAsync() > NewTechCount) + if (await AyaNova.Biz.UserBiz.ActiveTechUserCountAsync() > NewTechCount) { //attempt to set enough of the eldest last login techs to inactive await AyaNova.Biz.UserBiz.DeActivateExcessiveTechs(NewTechCount, log); - if (await AyaNova.Biz.UserBiz.ActiveCountAsync() > NewTechCount) + if (await AyaNova.Biz.UserBiz.ActiveTechUserCountAsync() > NewTechCount) throw new ApplicationException("E1020 - Can't install key, too many active techs and / or subcontractors in database. Deactivate enough to install key."); } +#endif + + //Update current license CurrentInDbKeyRecord.Key = RawTextNewKey;