diff --git a/.vscode/launch.json b/.vscode/launch.json index 379d2046..47a5435c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -44,7 +44,7 @@ //"AYANOVA_LOG_LEVEL": "Debug", "AYANOVA_DEFAULT_TRANSLATION": "en", //TRANSLATION MUST BE en for Integration TESTING - //"AYANOVA_PERMANENTLY_ERASE_DATABASE": "true", + "AYANOVA_PERMANENTLY_ERASE_DATABASE": "true", "AYANOVA_DB_CONNECTION": "Server=localhost;Username=postgres;Password=raven;Database=AyaNova;", "AYANOVA_USE_URLS": "http://*:7575;", "AYANOVA_FOLDER_USER_FILES": "c:\\temp\\RavenTestData\\userfiles", diff --git a/devdocs/todo.txt b/devdocs/todo.txt index 2d1a9d65..3b3a011e 100644 --- a/devdocs/todo.txt +++ b/devdocs/todo.txt @@ -71,6 +71,11 @@ todo: RAVEN new job LicenseCheck ################# + +todo: authentication login from IP address, it should really be an option or kept where it can be viewed but not overwhelm the log file + Maybe a switch to disable or mask it or fully enable so "AY_LOG_LOGIN" values "FULL" or "MASK" or "DEBUG_FULL" or "DEBUG_MASK" or "NONE" + Defaults to FULL + todo: permanently erase db startup thing, should it really exist? It will zap the dbid so a user might expect to just use their old license but it wont' fetch again we could issue a new key to replace with the new dbid and also issue a revoke key for the old dbid so that diff --git a/server/AyaNova/Controllers/AuthController.cs b/server/AyaNova/Controllers/AuthController.cs index 0fe08bd0..e56df79c 100644 --- a/server/AyaNova/Controllers/AuthController.cs +++ b/server/AyaNova/Controllers/AuthController.cs @@ -67,7 +67,7 @@ namespace AyaNova.Api.Controllers if (serverState.IsClosed && AyaNova.Core.License.ActiveKey.KeyDoesNotNeedAttention) - { + { return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason)); } @@ -169,11 +169,13 @@ namespace AyaNova.Api.Controllers //check if server closed //if it is it means we got here only because there is no license //and only *the* SuperUser account can login now - if(serverState.IsClosed){ + if (serverState.IsClosed) + { //if not SuperUser account then boot closed //SuperUser account is always ID 1 - if(u.Id!=1){ - return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); + if (u.Id != 1) + { + return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); } } //Restrict auth due to server state? @@ -222,9 +224,16 @@ namespace AyaNova.Api.Controllers //save auth token to ensure single sign on only u.CurrentAuthToken = token; + + u.LastLogin = DateTime.UtcNow; + await ct.SaveChangesAsync(); - log.LogDebug($"User number \"{u.Id}\" logged in from \"{Util.StringUtil.MaskIPAddress(HttpContext.Connection.RemoteIpAddress.ToString())}\" ok"); + //KEEP this, masked version of IP address + //Not sure if this is necessary or not but if it turns out to be then make it a boot option + // log.LogInformation($"User number \"{u.Id}\" logged in from \"{Util.StringUtil.MaskIPAddress(HttpContext.Connection.RemoteIpAddress.ToString())}\" ok"); + + log.LogInformation($"User \"{u.Name}\" logged in from \"{HttpContext.Connection.RemoteIpAddress.ToString()}\" ok"); return Ok(ApiOkResponse.Response(new diff --git a/server/AyaNova/biz/UserBiz.cs b/server/AyaNova/biz/UserBiz.cs index 51897a4b..740dcdef 100644 --- a/server/AyaNova/biz/UserBiz.cs +++ b/server/AyaNova/biz/UserBiz.cs @@ -40,6 +40,20 @@ namespace AyaNova.Biz } } + //Called by license processor when use downgrades to lesser amount of techs + internal static async Task DeActivateExcessiveTechs(int KeepThisManyActiveTechs) + { + using (AyContext ct = ServiceProviderProvider.DBContext) + { + var ActiveTechList = await ct.User.AsNoTracking().Where(z => z.Active == true && ( + z.UserType == UserType.Service || + z.UserType == UserType.ServiceContractor)).ToListAsync(); + + + } + + } + internal static UserBiz GetBiz(AyContext ct, Microsoft.AspNetCore.Http.HttpContext httpContext = null) { if (httpContext != null) diff --git a/server/AyaNova/models/User.cs b/server/AyaNova/models/User.cs index c8658e73..2d2ba46b 100644 --- a/server/AyaNova/models/User.cs +++ b/server/AyaNova/models/User.cs @@ -11,6 +11,7 @@ namespace AyaNova.Models public dtUser() { Tags = new List(); + LastLogin = DateTime.MinValue; } public long Id { get; set; } public uint Concurrency { get; set; } @@ -27,6 +28,8 @@ namespace AyaNova.Models public string Wiki { get; set; } public string CustomFields { get; set; } public List Tags { get; set; } + + public DateTime LastLogin { get; set; } }//eoc public class User : ICoreBizObjectModel @@ -39,6 +42,8 @@ namespace AyaNova.Models [Required, MaxLength(255)] public string Name { get; set; } + public DateTime LastLogin { get; set; } + public string Login { get; set; } public string Password { get; set; } diff --git a/server/AyaNova/util/AySchema.cs b/server/AyaNova/util/AySchema.cs index 4a7aca5d..ebc75d82 100644 --- a/server/AyaNova/util/AySchema.cs +++ b/server/AyaNova/util/AySchema.cs @@ -22,7 +22,7 @@ namespace AyaNova.Util //!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImporting WHEN NEW TABLES ADDED!!!! private const int DESIRED_SCHEMA_LEVEL = 11; - internal const long EXPECTED_COLUMN_COUNT = 324; + internal const long EXPECTED_COLUMN_COUNT = 325; internal const long EXPECTED_INDEX_COUNT = 134; //!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImporting WHEN NEW TABLES ADDED!!!! @@ -325,7 +325,7 @@ $BODY$; //Add user table await ExecQueryAsync("CREATE TABLE auser (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, active bool not null, name varchar(255) not null unique, " + - "login text not null unique, password text not null, salt text not null, roles integer not null, currentauthtoken text, " + + "lastlogin timestamp, login text not null unique, password text not null, salt text not null, roles integer not null, currentauthtoken text, " + "dlkey text, dlkeyexpire timestamp, usertype integer not null, employeenumber varchar(255), notes text, customerid bigint, " + "headofficeid bigint, subvendorid bigint, wiki text null, customfields text, tags varchar(255) ARRAY)"); diff --git a/server/AyaNova/util/License.cs b/server/AyaNova/util/License.cs index 1c265de6..2200a1f9 100644 --- a/server/AyaNova/util/License.cs +++ b/server/AyaNova/util/License.cs @@ -707,6 +707,9 @@ namespace AyaNova.Core //TODO: TECHCOUNT - new license causes exceeding count? if (await AyaNova.Biz.UserBiz.ActiveCountAsync() > ParsedNewKey.GetLicenseFeature(SERVICE_TECHS_FEATURE_NAME).Count) { + //Ok, the easy thing to do here is just set all techs inactive, but + //a trickier but probably better thing to do is set just enough techs inactive and choose them based + //on the oldest last login datetime first throw new ApplicationException("E1020 - Can't install key, too many active techs and / or subcontractors in database. Deactivate enough to install key."); }