More subscription license work allow logins addition

This commit is contained in:
2022-08-23 21:41:20 +00:00
parent ae3d576d40
commit e06334a175
13 changed files with 74 additions and 26 deletions

View File

@@ -6,7 +6,7 @@ If any packages have been changed in the release do a thorough security scan and
### Bump version numbers:
Search and replace 8.0.6
Search and replace 8.0.7
webapp,server,launcher, v8migrate (don't change v8migrate unless it has it's own code changes, it's version should be it's own thing other than major release changes etc)
Client end ayanova-version.js,

View File

@@ -139,7 +139,7 @@ TWO types makes the most sense after considering options:
- One time fee, user can use indefinitely
- self installed, hosted and maintained by customer
- least profitable for us long term if they don't buy a maint. subscription
- Without maintenance subscription, eligable for Minor updates only to fix bugs no new features so in other words they buy 8.0.6 they can upgrade to any 8.0.X version release, but not 8.1 as it will be new features added that don't break backward compatibility
- Without maintenance subscription, eligable for Minor updates only to fix bugs no new features so in other words they buy 8.0.7 they can upgrade to any 8.0.X version release, but not 8.1 as it will be new features added that don't break backward compatibility
- one-time payment, along with the option of a yearly maintenance fee.
- This is basically our current model but we allow upgrades for subscribers
- **HAS CODE IMPLICATIONS** upgrades need to check if allowed based on version number if no maintenance subscription _not_ on date of build.

View File

@@ -35,6 +35,16 @@ WIP >>>>>>>>>>>>>
todo: move the dbid to the very first position in the shareit order additional fields as only the first two will show in email and reporting
todo: register domain name myayanova.com for hanging subscriber servers off of
todo: rockfish not putting time limit on subscription keys, UI needs additions and shit for that
todo: restrict superuser account in some critical ways so it can't be used for day to day work, maybe no dashboard etc
nothing too serious that it breaks existing code but remove any features that it shouldn't be used for
Find a subtle way to do this particularly for subscription users
todo: superuser consuming a license theoretically but shouldn't so in a subscription mode it needs to be locked down as to what it can be used for, some critical features should block it from use
fuck! Actually, just automatically deduct it from the count, whatever the count is remove one for superuser (or maybe in query filter OUT the superuser id 1!!!!)
todo: customer contact consuming a subscription license always because it doesn't knwo if they are a login or just a contact, maybe solution is to not set a login name if they arebn't a login customer
and change the counting code to ignore no login name users (but only for the customer contact count, not the inside staff count or that would be used to circumvent licening (or do we care? hmmm))
todo: TEST subscription and perpetual license code
@@ -42,7 +52,8 @@ todo: TEST subscription and perpetual license code
Does it prevent changing a user type? (direct db meddling)
Does it prevent installing a new license when too few for existing active?
Does it communicate this well to the user?
@@ -1259,6 +1270,6 @@ https://www.ayanova.com/download/next/ayanova-linux-x64-server.zip
https://www.ayanova.com/download/next/ayanova-windows-x64-lan-setup.exe
Current v8 docs home: https://www.ayanova.com/docs/next
BUILD 8.0.6 CHANGES OF NOTE
BUILD 8.0.7 CHANGES OF NOTE
Subscription / perpetual license code and stuff

View File

@@ -1,7 +1,7 @@
; LAN install for internal network use only
#define MyAppName "AyaNova server"
#define MyAppVersion "8.0.6"
#define MyAppVersion "8.0.7"
#define MyAppPublisher "Ground Zero Tech-Works, Inc."
#define MyAppURL "https://ayanova.com/"
#define MyAppLauncherExeName "ayanova-launcher.exe"

View File

@@ -3,7 +3,7 @@
; external to lan requires different config
#define MyAppName "AyaNova"
#define MyAppVersion "8.0.6"
#define MyAppVersion "8.0.7"
#define MyAppPublisher "Ground Zero Tech-Works, Inc."
#define MyAppURL "https://ayanova.com/"
#define MyAppLauncherExeName "ayanova-launcher.exe"

View File

@@ -4,8 +4,8 @@
</PropertyGroup>
<PropertyGroup>
<GenerateFullPaths>true</GenerateFullPaths>
<Version>8.0.6</Version>
<FileVersion>8.0.6.0</FileVersion>
<Version>8.0.7</Version>
<FileVersion>8.0.7.0</FileVersion>
<ApplicationIcon>ayanova.ico</ApplicationIcon>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
<noWarn>1591</noWarn>

View File

@@ -87,7 +87,7 @@ namespace AyaNova.Api.Controllers
//Multiple users are allowed the same password and login
//Salt will differentiate them so get all users that match login, then try to match pw
var users = await ct.User.Where(z => z.Login == creds.Login && z.Active == true).ToListAsync();
var users = await ct.User.Where(z => z.Login == creds.Login && z.Active == true && z.AllowLogin == true).ToListAsync();
foreach (User u in users)
{
@@ -168,7 +168,7 @@ namespace AyaNova.Api.Controllers
}
//Match to temp token that would have been set by initial credentialed login for 2fa User
var user = await ct.User.Where(z => z.TempToken == pin.TempToken && z.Active == true && z.TwoFactorEnabled == true).FirstOrDefaultAsync();
var user = await ct.User.Where(z => z.TempToken == pin.TempToken && z.Active == true && z.AllowLogin==true && z.TwoFactorEnabled == true).FirstOrDefaultAsync();
if (user != null)
@@ -393,7 +393,7 @@ namespace AyaNova.Api.Controllers
{
//If the user is inactive they may not login
if (!u.Active)
if (!u.Active || !u.AllowLogin)
{
//respond like bad creds so as not to leak information
await Task.Delay(AyaNova.Util.ServerBootConfig.FAILED_AUTH_DELAY);

View File

@@ -21,6 +21,7 @@ namespace AyaNova.Biz
//ILogger log = AyaNova.Util.ApplicationLogging.CreateLogger("PrimeData");
User u = new User();
u.Active = true;
u.AllowLogin=true;
u.Name = "AyaNova SuperUser";
u.Salt = Hasher.GenerateSalt();
u.Login = "superuser";

View File

@@ -42,7 +42,8 @@ namespace AyaNova.Biz
{
using (AyContext ct = ServiceProviderProvider.DBContext)
{
var ret = await ct.User.AsNoTracking().Where(z => z.Active == true && (
//all users who are not the superuser, active and not a customer or headoffice
var ret = await ct.User.AsNoTracking().Where(z => z.Id != 1 && z.Active == true && (
z.UserType != UserType.Customer &&
z.UserType != UserType.HeadOffice)).LongCountAsync();
return ret;
@@ -54,7 +55,9 @@ namespace AyaNova.Biz
{
using (AyContext ct = ServiceProviderProvider.DBContext)
{
var ret = await ct.User.AsNoTracking().Where(z => z.Active == true && (
//all users who are customer or head office, active and have a login name set
var ret = await ct.User.AsNoTracking().Where(z => z.Login != null && z.Active == true && (
z.UserType == UserType.Customer ||
z.UserType == UserType.HeadOffice)).LongCountAsync();
return ret;
@@ -864,6 +867,9 @@ namespace AyaNova.Biz
if (proposedObj.Active != currentObj.Active)
AddError(ApiErrorCode.NOT_AUTHORIZED, "Active");
if (proposedObj.AllowLogin != currentObj.AllowLogin)
AddError(ApiErrorCode.NOT_AUTHORIZED, "AllowLogin");
if (proposedObj.Name != currentObj.Name)
AddError(ApiErrorCode.NOT_AUTHORIZED, "Name");

View File

@@ -17,6 +17,7 @@ namespace AyaNova.Models
public long Id { get; set; }
public uint Concurrency { get; set; }
public bool Active { get; set; }
public bool AllowLogin { get; set; }
[Required, MaxLength(255)]
public string Name { get; set; }
public AuthorizationRoles Roles { get; set; }
@@ -54,6 +55,7 @@ namespace AyaNova.Models
[Required]
public bool Active { get; set; }
public bool AllowLogin { get; set; }
[Required, MaxLength(255)]
public string Name { get; set; }
public DateTime? LastLogin { get; set; }
@@ -116,12 +118,12 @@ namespace AyaNova.Models
[JsonIgnore]
public Vendor Vendor { get; set; }
public User()
{
Tags = new List<string>();
}

View File

@@ -20,7 +20,7 @@ namespace AyaNova.Util
/////////// CHANGE THIS ON NEW SCHEMA UPDATE ////////////////////
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImportingAsync WHEN NEW TABLES ADDED!!!!
private const int DESIRED_SCHEMA_LEVEL = 5;
private const int DESIRED_SCHEMA_LEVEL = 6;
internal const long EXPECTED_COLUMN_COUNT = 1376;
internal const long EXPECTED_INDEX_COUNT = 161;
@@ -1482,7 +1482,7 @@ $BODY$ LANGUAGE PLPGSQL STABLE");
//////////////////////////////////////////////////
//
// 8.0.6 Subscription license trans keys
// 8.0.7 Subscription license trans keys
//
if (currentSchema < 5)
{
@@ -1512,6 +1512,34 @@ $BODY$ LANGUAGE PLPGSQL STABLE");
//////////////////////////////////////////////////
//
// 8.0.7 additions for customer contact licensing (allowlogin)
//
if (currentSchema < 6)
{
LogUpdateMessage(log);
await ExecQueryAsync("ALTER TABLE auser ADD column allowlogin BOOL");
await ExecQueryAsync("UPDTE TABLE auser SET allowlogin=true WHERE active=true");
//english translations
await ExecQueryAsync("INSERT INTO atranslationitem(translationid,key,display) SELECT t.id, 'AllowLogin', 'Allow login' FROM atranslation t where t.baselanguage = 'en'");
//spanish translations
await ExecQueryAsync("INSERT INTO atranslationitem(translationid,key,display) SELECT t.id, 'AllowLogin', 'Permitir acceso' FROM atranslation t where t.baselanguage = 'es'");
//french translations
await ExecQueryAsync("INSERT INTO atranslationitem(translationid,key,display) SELECT t.id, 'AllowLogin', 'Autoriser la connexion' FROM atranslation t where t.baselanguage = 'fr'");
//german translations
await ExecQueryAsync("INSERT INTO atranslationitem(translationid,key,display) SELECT t.id, 'AllowLogin', 'Login erlauben' FROM atranslation t where t.baselanguage = 'de'");
await SetSchemaLevelAsync(++currentSchema);
}
//#########################################
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImporting WHEN NEW TABLES ADDED!!!!

View File

@@ -5,7 +5,7 @@ namespace AyaNova.Util
/// </summary>
internal static class AyaNovaVersion
{
public const string VersionString = "8.0.6";
public const string VersionString = "8.0.7";
public const string FullNameAndVersion = "AyaNova server " + VersionString;
public const string CurrentApiVersion="v8";
}//eoc

View File

@@ -123,7 +123,7 @@ namespace AyaNova.Core
/// Fetch the license status of the feature in question
/// </summary>
/// <param name="Feature"></param>
/// <returns>LicenseFeature object or null if there is no license</returns>
/// <returns>LicenseFeature object or null if there is no matching license feature or license is missing</returns>
public LicenseFeature GetLicenseFeature(string Feature)
{
if (IsEmpty)
@@ -145,7 +145,7 @@ namespace AyaNova.Core
{
get
{
return GetLicenseFeature(SERVICE_TECHS_FEATURE_NAME).Count;
return GetLicenseFeature(SERVICE_TECHS_FEATURE_NAME)?.Count ?? 0;
}
}
@@ -153,7 +153,7 @@ namespace AyaNova.Core
{
get
{
return GetLicenseFeature(ACTIVE_INTERNAL_USERS_FEATURE_NAME).Count;
return GetLicenseFeature(ACTIVE_INTERNAL_USERS_FEATURE_NAME)?.Count ?? 0;
}
}
@@ -161,7 +161,7 @@ namespace AyaNova.Core
{
get
{
return GetLicenseFeature(ACTIVE_CUSTOMER_USERS_FEATURE_NAME).Count;
return GetLicenseFeature(ACTIVE_CUSTOMER_USERS_FEATURE_NAME)?.Count ?? 0;
}
}
@@ -855,10 +855,10 @@ namespace AyaNova.Core
//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 NewInsideUserLicensedCount = ParsedNewKey.ActiveInternalUsersCount;
long ExistingActiveInsideUserCount = await AyaNova.Biz.UserBiz.ActiveInternalUserCountAsync();
long NewCustomerLicensedCount = ParsedNewKey.GetLicenseFeature(ACTIVE_CUSTOMER_USERS_FEATURE_NAME).Count;
long NewCustomerLicensedCount = ParsedNewKey.ActiveCustomerContactUsersCount;
long ExistingCustomerUserCount = await AyaNova.Biz.UserBiz.ActiveCustomerContactUserCountAsync();
string err = "E1020 - Can't install license: ";
bool throwit = false;
@@ -879,7 +879,7 @@ namespace AyaNova.Core
#else
//PERPETUAL, vet the TECHCOUNT - new license causes exceeding count?
long NewTechCount = ParsedNewKey.GetLicenseFeature(SERVICE_TECHS_FEATURE_NAME).Count;
long NewTechCount = ParsedNewKey.ActiveTechsCount;
if (await AyaNova.Biz.UserBiz.ActiveTechUserCountAsync() > NewTechCount)
{
//attempt to set enough of the eldest last login techs to inactive