diff --git a/server/AyaNova/Controllers/UserController.cs b/server/AyaNova/Controllers/UserController.cs index 9c8b3732..3031eca1 100644 --- a/server/AyaNova/Controllers/UserController.cs +++ b/server/AyaNova/Controllers/UserController.cs @@ -86,6 +86,7 @@ namespace AyaNova.Api.Controllers /// /// Put (update) User + /// (Login and / or Password are not changed if set to null / omitted) /// /// /// diff --git a/server/AyaNova/biz/BizRoles.cs b/server/AyaNova/biz/BizRoles.cs index 46a4ccd3..a55520cf 100644 --- a/server/AyaNova/biz/BizRoles.cs +++ b/server/AyaNova/biz/BizRoles.cs @@ -432,7 +432,7 @@ namespace AyaNova.Biz //throw new System.ArgumentException("BizRoles::Constructor - roles were modified from last snapshot for client!!!"); // log = { - ((ILogger)AyaNova.Util.ApplicationLogging.CreateLogger("BizRoles.cs")).LogError("BizRoles::Constructor - roles were modified from last snapshot for client!!!"); + ((ILogger)AyaNova.Util.ApplicationLogging.CreateLogger("BizRoles.cs")).LogWarning("BizRoles::Constructor - roles were modified from last snapshot for client!!!"); } } diff --git a/server/AyaNova/biz/UserBiz.cs b/server/AyaNova/biz/UserBiz.cs index 352e4b36..cb821e24 100644 --- a/server/AyaNova/biz/UserBiz.cs +++ b/server/AyaNova/biz/UserBiz.cs @@ -49,6 +49,19 @@ namespace AyaNova.Biz //CREATE internal async Task CreateAsync(User inObj) { + //password and login are optional but in the sense that they can be left out in a PUT + // but if left out here we need to generate a random value instead so they can't login but the code is happy + //because a login name and password are required always + if (string.IsNullOrWhiteSpace(inObj.Password)) + { + inObj.Password = Hasher.GenerateSalt();//set it to some big random value + } + + if (string.IsNullOrWhiteSpace(inObj.Login)) + { + inObj.Login = Hasher.GenerateSalt();//set it to some big random value + } + //This is a new user so it will have been posted with a password in plaintext which needs to be salted and hashed inObj.Salt = Hasher.GenerateSalt(); inObj.Password = Hasher.hash(inObj.Salt, inObj.Password); @@ -88,6 +101,10 @@ namespace AyaNova.Biz //TAGS await TagUtil.ProcessUpdateTagsInRepositoryAsync(ct, inObj.Tags, null); + //Accept, but never return a User's password or login + inObj.Password = null; + inObj.Login = null; + return inObj; } @@ -128,6 +145,7 @@ namespace AyaNova.Biz dbObj.Tags = TagUtil.NormalizeTags(dbObj.Tags); dbObj.CustomFields = JsonUtil.CompactJson(dbObj.CustomFields); + //NOTE: It's valid to call this without intending to change login or password (null values) //Is the user updating the password? if (!string.IsNullOrWhiteSpace(inObj.Password) && SnapshotOfOriginalDBObj.Password != inObj.Password) { @@ -140,6 +158,17 @@ namespace AyaNova.Biz dbObj.Password = SnapshotOfOriginalDBObj.Password; dbObj.Salt = SnapshotOfOriginalDBObj.Salt; } + //Updating login? + if (!string.IsNullOrWhiteSpace(inObj.Login)) + { + //YES Login is being updated: + dbObj.Login=inObj.Login; + } + else + { + //No, use the original value + dbObj.Login = SnapshotOfOriginalDBObj.Login; + } //Set "original" value of concurrency token to input token @@ -183,6 +212,18 @@ namespace AyaNova.Biz dbObj.Password = Hasher.hash(dbObj.Salt, dbObj.Password); } + //Updating login? + if (!string.IsNullOrWhiteSpace(dbObj.Login) && dbObj.Login != SnapshotOfOriginalDBObj.Login) + { + //YES Login is being updated: + dbObj.Login=SnapshotOfOriginalDBObj.Login; + } + else + { + //No, use the original value + dbObj.Login = SnapshotOfOriginalDBObj.Login; + } + ct.Entry(dbObj).OriginalValues["ConcurrencyToken"] = concurrencyToken; await ValidateAsync(dbObj, SnapshotOfOriginalDBObj); if (HasErrors) diff --git a/server/AyaNova/models/AyContext.cs b/server/AyaNova/models/AyContext.cs index 05c69569..aa9068c1 100644 --- a/server/AyaNova/models/AyContext.cs +++ b/server/AyaNova/models/AyContext.cs @@ -5,11 +5,13 @@ namespace AyaNova.Models { public partial class AyContext : DbContext { + public virtual DbSet User { get; set; } + public virtual DbSet UserOptions { get; set; } public virtual DbSet Widget { get; set; } public virtual DbSet GlobalBizSettings { get; set; } public virtual DbSet Event { get; set; } public virtual DbSet SearchDictionary { get; set; } - public virtual DbSet SearchKey { get; set; } + public virtual DbSet SearchKey { get; set; } public virtual DbSet FileAttachment { get; set; } public virtual DbSet OpsJob { get; set; } public virtual DbSet OpsJobLog { get; set; } @@ -19,8 +21,6 @@ namespace AyaNova.Models public virtual DbSet Tag { get; set; } public virtual DbSet FormCustom { get; set; } public virtual DbSet PickListTemplate { get; set; } - public virtual DbSet User { get; set; } - public virtual DbSet UserOptions { get; set; } public virtual DbSet License { get; set; } public virtual DbSet Customer { get; set; } public virtual DbSet Contract { get; set; } diff --git a/server/AyaNova/models/User.cs b/server/AyaNova/models/User.cs index c8ee0bb9..ea7dc015 100644 --- a/server/AyaNova/models/User.cs +++ b/server/AyaNova/models/User.cs @@ -15,9 +15,9 @@ namespace AyaNova.Models public bool Active { get; set; } [Required, MaxLength(255)] public string Name { get; set; } - [Required] + //[Required] public string Login { get; set; } - [Required] + //[Required] public string Password { get; set; } public string Salt { get; set; } [Required] diff --git a/server/AyaNova/util/AySchema.cs b/server/AyaNova/util/AySchema.cs index a0a6a3bd..22bc8b77 100644 --- a/server/AyaNova/util/AySchema.cs +++ b/server/AyaNova/util/AySchema.cs @@ -181,7 +181,7 @@ namespace AyaNova.Util await ExecQueryAsync("CREATE TABLE auseroptions (id BIGSERIAL PRIMARY KEY, " + "userid bigint not null, translationid bigint not null REFERENCES atranslation (id), languageoverride text, timezoneoverride text, currencyname text, hour12 bool not null, emailaddress text, uicolor varchar(12) not null default '#000000')"); - + //Prime the db with the default MANAGER account await AyaNova.Biz.PrimeData.PrimeManagerAccount(ct); @@ -454,7 +454,7 @@ namespace AyaNova.Util await ExecQueryAsync("CREATE UNIQUE INDEX apmtemplateitem_name_id_idx ON apmtemplateitem (id, name);"); await ExecQueryAsync("CREATE INDEX apmtemplateitem_tags ON apmtemplateitem using GIN(tags)"); - + await SetSchemaLevelAsync(++currentSchema); } diff --git a/server/AyaNova/util/DbUtil.cs b/server/AyaNova/util/DbUtil.cs index 24e4ab05..3059f66e 100644 --- a/server/AyaNova/util/DbUtil.cs +++ b/server/AyaNova/util/DbUtil.cs @@ -293,7 +293,7 @@ namespace AyaNova.Util //REMOVE ALL DATA with few exceptions of manager user, license, schema tables //and job logs because this is called by job code - + await EraseTableAsync("atranslationitem", conn); await EraseTableAsync("atranslation", conn); //Load the default TRANSLATIONS @@ -353,7 +353,7 @@ namespace AyaNova.Util using (var cmd = new Npgsql.NpgsqlCommand()) { cmd.Connection = conn; - cmd.CommandText = "TRUNCATE \"" + sTable + "\" RESTART IDENTITY CASCADE;"; + cmd.CommandText = "TRUNCATE \"" + sTable + "\" RESTART IDENTITY;"; await cmd.ExecuteNonQueryAsync(); } }