diff --git a/server/AyaNova/biz/UserBiz.cs b/server/AyaNova/biz/UserBiz.cs index bbe7a38e..9a72ea05 100644 --- a/server/AyaNova/biz/UserBiz.cs +++ b/server/AyaNova/biz/UserBiz.cs @@ -40,7 +40,7 @@ namespace AyaNova.Biz inObj.Salt = Hasher.GenerateSalt(); inObj.Password = Hasher.hash(inObj.Salt, inObj.Password); - Validate(inObj, true); + Validate(inObj, null); if (HasErrors) return null; else @@ -153,14 +153,27 @@ namespace AyaNova.Biz //put internal bool Put(User dbObj, User inObj) { + //Replace the db object with the PUT object skipping the password and salt and Id fields + CopyObject.Copy(inObj, dbObj, "Id, Salt, Password"); + + //Is the user updating the password? + if (!string.IsNullOrWhiteSpace(inObj.Password) && dbObj.Password != inObj.Password) + { + //YES password is being updated: + inObj.Password = Hasher.hash(inObj.Salt, inObj.Password); + } + else + { + //No, use the db password value + //Should not require any code to run as it will retain it's db value + } + - //Replace the db object with the PUT object - CopyObject.Copy(inObj, dbObj, "Id"); //Set "original" value of concurrency token to input token //this will allow EF to check it out ct.Entry(dbObj).OriginalValues["ConcurrencyToken"] = inObj.ConcurrencyToken; - Validate(dbObj, false); + Validate(dbObj, inObj); if (HasErrors) return false; @@ -170,10 +183,17 @@ namespace AyaNova.Biz //patch internal bool Patch(User dbObj, JsonPatchDocument objectPatch, uint concurrencyToken) { + //TODO: objectPatch handle patching password + + //make a snapshot of the original for validation but update the original to preserve workflow + + User snapshotObj=null; + CopyObject.Copy(dbObj, snapshotObj); + //Do the patching objectPatch.ApplyTo(dbObj); ct.Entry(dbObj).OriginalValues["ConcurrencyToken"] = concurrencyToken; - Validate(dbObj, false); + Validate(dbObj, snapshotObj); if (HasErrors) return false; @@ -212,14 +232,17 @@ namespace AyaNova.Biz // //Can save or update? - private void Validate(User inObj, bool isNew) + private void Validate(User proposedObj, User currentObj) { //run validation and biz rules - if (isNew) + bool isNew = currentObj == null; + + + if (isNew) //Yes, no currentObj { //Not sure why we would care about this particular rule or why I added it? Maybe it's from widget? // //NEW Users must be active - // if (((bool)inObj.Active) == false) + // if (((bool)proposedObj.Active) == false) // { // AddError(ValidationErrorType.InvalidValue, "Active", "New User must be active"); // } @@ -228,23 +251,23 @@ namespace AyaNova.Biz //OwnerId required if (!isNew) { - if (inObj.OwnerId == 0) + if (proposedObj.OwnerId == 0) AddError(ValidationErrorType.RequiredPropertyEmpty, "OwnerId"); } //Name required - if (string.IsNullOrWhiteSpace(inObj.Name)) + if (string.IsNullOrWhiteSpace(proposedObj.Name)) AddError(ValidationErrorType.RequiredPropertyEmpty, "Name"); //Name must be less than 255 characters - if (inObj.Name.Length > 255) + if (proposedObj.Name.Length > 255) AddError(ValidationErrorType.LengthExceeded, "Name", "255 max"); //If name is otherwise OK, check that name is unique if (!PropertyHasErrors("Name")) { //Use Any command is efficient way to check existance, it doesn't return the record, just a true or false - if (ct.User.Any(m => m.Name == inObj.Name && m.Id != inObj.Id)) + if (ct.User.Any(m => m.Name == proposedObj.Name && m.Id != proposedObj.Id)) { AddError(ValidationErrorType.NotUnique, "Name"); } @@ -278,15 +301,15 @@ namespace AyaNova.Biz need to check open workorders and any other critical items when de-activating a user */ - if (!inObj.UserType.IsValid()) + if (!proposedObj.UserType.IsValid()) { AddError(ValidationErrorType.InvalidValue, "UserType"); } //Validate client type user - if (!V7ValidationImportMode && inObj.UserType == UserType.Client) + if (!V7ValidationImportMode && proposedObj.UserType == UserType.Client) { - if (inObj.ClientId == null || inObj.ClientId == 0) + if (proposedObj.ClientId == null || proposedObj.ClientId == 0) { AddError(ValidationErrorType.RequiredPropertyEmpty, "ClientId"); } @@ -298,9 +321,9 @@ namespace AyaNova.Biz } //Validate headoffice type user - if (!V7ValidationImportMode && inObj.UserType == UserType.HeadOffice) + if (!V7ValidationImportMode && proposedObj.UserType == UserType.HeadOffice) { - if (inObj.HeadOfficeId == null || inObj.HeadOfficeId == 0) + if (proposedObj.HeadOfficeId == null || proposedObj.HeadOfficeId == 0) { AddError(ValidationErrorType.RequiredPropertyEmpty, "HeadOfficeId"); } @@ -312,9 +335,9 @@ namespace AyaNova.Biz } //Validate headoffice type user - if (!V7ValidationImportMode && inObj.UserType == UserType.Subcontractor) + if (!V7ValidationImportMode && proposedObj.UserType == UserType.Subcontractor) { - if (inObj.SubVendorId == null || inObj.SubVendorId == 0) + if (proposedObj.SubVendorId == null || proposedObj.SubVendorId == 0) { AddError(ValidationErrorType.RequiredPropertyEmpty, "SubVendorId"); } @@ -325,13 +348,13 @@ namespace AyaNova.Biz } } - if (!inObj.Roles.IsValid()) + if (!proposedObj.Roles.IsValid()) { AddError(ValidationErrorType.InvalidValue, "Roles"); } //Optional employee number field must be less than 255 characters - if (!string.IsNullOrWhiteSpace(inObj.EmployeeNumber) && inObj.EmployeeNumber.Length > 255) + if (!string.IsNullOrWhiteSpace(proposedObj.EmployeeNumber) && proposedObj.EmployeeNumber.Length > 255) AddError(ValidationErrorType.LengthExceeded, "EmployeeNumber", "255 max"); diff --git a/test/raven-integration/User/UserCrud.cs b/test/raven-integration/User/UserCrud.cs index b2631f73..45f537e5 100644 --- a/test/raven-integration/User/UserCrud.cs +++ b/test/raven-integration/User/UserCrud.cs @@ -31,12 +31,16 @@ namespace raven_integration Util.ValidateDataReturnResponseOk(r1); long d1Id = r1.ObjectResponse["result"]["id"].Value(); -HERE + dynamic d2 = new JObject(); d2.name = Util.Uniquify("Second Test User"); - d2.dollarAmount = 2.22m; - d2.active = true; - d2.roles = 0; + d2.ownerId = 1L; + d2.active=true; + d2.login=Util.Uniquify("LOGIN"); + d2.password=Util.Uniquify("PASSWORD"); + d2.roles=0;//norole + d2.localeId=1;//random locale + d2.userType=3;//non scheduleable ApiResponse r2 = await Util.PostAsync("User", await Util.GetTokenAsync("manager", "l3tm3in"), d2.ToString()); Util.ValidateDataReturnResponseOk(r2);