This commit is contained in:
2018-09-05 18:57:55 +00:00
parent 620a27d35c
commit da9814868b
3 changed files with 94 additions and 79 deletions

View File

@@ -153,19 +153,24 @@ 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");
//Get a snapshot of the original db value object before changes
User SnapshotObj = new User();
CopyObject.Copy(dbObj, SnapshotObj);
//Update the db object with the PUT object values
CopyObject.Copy(inObj, dbObj, "Id, Salt");
//Is the user updating the password?
if (!string.IsNullOrWhiteSpace(inObj.Password) && dbObj.Password != inObj.Password)
if (!string.IsNullOrWhiteSpace(inObj.Password) && SnapshotObj.Password != inObj.Password)
{
//YES password is being updated:
inObj.Password = Hasher.hash(inObj.Salt, inObj.Password);
dbObj.Password = Hasher.hash(SnapshotObj.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
//No, use the snapshot password value
dbObj.Password = SnapshotObj.Password;
dbObj.Salt = SnapshotObj.Salt;
}
@@ -173,7 +178,7 @@ namespace AyaNova.Biz
//this will allow EF to check it out
ct.Entry(dbObj).OriginalValues["ConcurrencyToken"] = inObj.ConcurrencyToken;
Validate(dbObj, inObj);
Validate(dbObj, SnapshotObj);
if (HasErrors)
return false;
@@ -183,15 +188,20 @@ namespace AyaNova.Biz
//patch
internal bool Patch(User dbObj, JsonPatchDocument<User> 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;
//make a snapshot of the original for validation but update the original to preserve workflow
User snapshotObj = new User();
CopyObject.Copy(dbObj, snapshotObj);
//Do the patching
objectPatch.ApplyTo(dbObj);
//Is the user patching the password?
if (!string.IsNullOrWhiteSpace(dbObj.Password) && dbObj.Password != snapshotObj.Password)
{
//YES password is being updated:
dbObj.Password = Hasher.hash(dbObj.Salt, dbObj.Password);
}
ct.Entry(dbObj).OriginalValues["ConcurrencyToken"] = concurrencyToken;
Validate(dbObj, snapshotObj);
if (HasErrors)
@@ -237,7 +247,7 @@ namespace AyaNova.Biz
//run validation and biz rules
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?

View File

@@ -22,7 +22,10 @@ namespace AyaNova.Util
{
string[] excluded = null;
if (!string.IsNullOrEmpty(excludedProperties))
{
excludedProperties=excludedProperties.Replace(", ", ",").Replace(" ,",",").Trim();
excluded = excludedProperties.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
}
MemberInfo[] miT = target.GetType().GetMembers(memberAccess);
foreach (MemberInfo Field in miT)

View File

@@ -15,44 +15,44 @@ namespace raven_integration
[Fact]
public async void CRUD()
{
//CREATE
dynamic d1 = new JObject();
d1.name = Util.Uniquify("First Test User");
d1.ownerId = 1L;
d1.active=true;
d1.login=Util.Uniquify("LOGIN");
d1.password=Util.Uniquify("PASSWORD");
d1.roles=0;//norole
d1.localeId=1;//random locale
d1.userType=3;//non scheduleable
dynamic D1 = new JObject();
D1.name = Util.Uniquify("First Test User");
D1.ownerId = 1L;
D1.active = true;
D1.login = Util.Uniquify("LOGIN");
D1.password = Util.Uniquify("PASSWORD");
D1.roles = 0;//norole
D1.localeId = 1;//random locale
D1.userType = 3;//non scheduleable
ApiResponse r1 = await Util.PostAsync("User", await Util.GetTokenAsync("manager", "l3tm3in"), d1.ToString());
Util.ValidateDataReturnResponseOk(r1);
long d1Id = r1.ObjectResponse["result"]["id"].Value<long>();
ApiResponse R1 = await Util.PostAsync("User", await Util.GetTokenAsync("manager", "l3tm3in"), D1.ToString());
Util.ValidateDataReturnResponseOk(R1);
long d1Id = R1.ObjectResponse["result"]["id"].Value<long>();
dynamic d2 = new JObject();
d2.name = Util.Uniquify("Second Test User");
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
dynamic D2 = new JObject();
D2.name = Util.Uniquify("Second Test User");
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);
long d2Id = r2.ObjectResponse["result"]["id"].Value<long>();
ApiResponse R2 = await Util.PostAsync("User", await Util.GetTokenAsync("manager", "l3tm3in"), D2.ToString());
Util.ValidateDataReturnResponseOk(R2);
long d2Id = R2.ObjectResponse["result"]["id"].Value<long>();
//RETRIEVE
//Get one
ApiResponse r3 = await Util.GetAsync("User/" + d2Id.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"));
Util.ValidateDataReturnResponseOk(r3);
r3.ObjectResponse["result"]["name"].Value<string>().Should().Be(d2.name.ToString());
ApiResponse R3 = await Util.GetAsync("User/" + d2Id.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"));
Util.ValidateDataReturnResponseOk(R3);
R3.ObjectResponse["result"]["name"].Value<string>().Should().Be(D2.name.ToString());
@@ -60,16 +60,16 @@ namespace raven_integration
//PUT
//update w2id
d2.name = Util.Uniquify("UPDATED VIA PUT SECOND TEST User");
d2.OwnerId = 1;
d2.concurrencyToken = r2.ObjectResponse["result"]["concurrencyToken"].Value<uint>();
ApiResponse PUTTestResponse = await Util.PutAsync("User/" + d2Id.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"), d2.ToString());
D2.name = Util.Uniquify("UPDATED VIA PUT SECOND TEST User");
D2.OwnerId = 1;
D2.concurrencyToken = R2.ObjectResponse["result"]["concurrencyToken"].Value<uint>();
ApiResponse PUTTestResponse = await Util.PutAsync("User/" + d2Id.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"), D2.ToString());
Util.ValidateHTTPStatusCode(PUTTestResponse, 200);
//check PUT worked
ApiResponse checkPUTWorked = await Util.GetAsync("User/" + d2Id.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"));
Util.ValidateNoErrorInResponse(checkPUTWorked);
checkPUTWorked.ObjectResponse["result"]["name"].Value<string>().Should().Be(d2.name.ToString());
checkPUTWorked.ObjectResponse["result"]["name"].Value<string>().Should().Be(D2.name.ToString());
uint concurrencyToken = PUTTestResponse.ObjectResponse["result"]["concurrencyToken"].Value<uint>();
//PATCH
@@ -89,7 +89,7 @@ namespace raven_integration
}
//TODO: Test password updating code
@@ -101,8 +101,8 @@ namespace raven_integration
{
//Get non existant
//Should return status code 404, api error code 2010
ApiResponse a = await Util.GetAsync("User/999999", await Util.GetTokenAsync("manager", "l3tm3in"));
Util.ValidateResponseNotFound(a);
ApiResponse R = await Util.GetAsync("User/999999", await Util.GetTokenAsync("manager", "l3tm3in"));
Util.ValidateResponseNotFound(R);
}
/// <summary>
@@ -113,8 +113,8 @@ namespace raven_integration
{
//Get non existant
//Should return status code 400, api error code 2200 and a first target in details of "id"
ApiResponse a = await Util.GetAsync("User/2q2", await Util.GetTokenAsync("manager", "l3tm3in"));
Util.ValidateBadModelStateResponse(a, "id");
ApiResponse R = await Util.GetAsync("User/2q2", await Util.GetTokenAsync("manager", "l3tm3in"));
Util.ValidateBadModelStateResponse(R, "id");
}
@@ -128,29 +128,29 @@ namespace raven_integration
[Fact]
public async void PutConcurrencyViolationShouldFail()
{
//CREATE
dynamic D = new JObject();
D.name = Util.Uniquify("PutConcurrencyViolationShouldFail");
D.ownerId = 1L;
D.active = true;
D.login = Util.Uniquify("LOGIN");
D.password = Util.Uniquify("PASSWORD");
D.roles = 0;//norole
D.localeId = 1;//random locale
D.userType = 3;//non scheduleable
//CREATE
dynamic w2 = new JObject();
w2.name = Util.Uniquify("PutConcurrencyViolationShouldFail");
w2.dollarAmount = 2.22m;
w2.active = true;
w2.roles = 0;
ApiResponse r2 = await Util.PostAsync("User", await Util.GetTokenAsync("manager", "l3tm3in"), w2.ToString());
Util.ValidateDataReturnResponseOk(r2);
long w2Id = r2.ObjectResponse["result"]["id"].Value<long>();
uint OriginalConcurrencyToken = r2.ObjectResponse["result"]["concurrencyToken"].Value<uint>();
ApiResponse R = await Util.PostAsync("User", await Util.GetTokenAsync("manager", "l3tm3in"), D.ToString());
Util.ValidateDataReturnResponseOk(R);
long D1Id = R.ObjectResponse["result"]["id"].Value<long>();
uint OriginalConcurrencyToken = R.ObjectResponse["result"]["concurrencyToken"].Value<uint>();
//UPDATE
//PUT
w2.name = Util.Uniquify("PutConcurrencyViolationShouldFail UPDATE VIA PUT ");
w2.OwnerId = 1;
w2.concurrencyToken = OriginalConcurrencyToken - 1;//bad token
ApiResponse PUTTestResponse = await Util.PutAsync("User/" + w2Id.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"), w2.ToString());
D.name = Util.Uniquify("PutConcurrencyViolationShouldFail UPDATE VIA PUT ");
D.concurrencyToken = OriginalConcurrencyToken - 1;//bad token
ApiResponse PUTTestResponse = await Util.PutAsync("User/" + D1Id.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"), D.ToString());
Util.ValidateConcurrencyError(PUTTestResponse);
@@ -165,19 +165,21 @@ namespace raven_integration
[Fact]
public async void PatchConcurrencyViolationShouldFail()
{
//CREATE
dynamic D = new JObject();
D.name = Util.Uniquify("PatchConcurrencyViolationShouldFail");
D.ownerId = 1L;
D.active = true;
D.login = Util.Uniquify("LOGIN");
D.password = Util.Uniquify("PASSWORD");
D.roles = 0;//norole
D.localeId = 1;//random locale
D.userType = 3;//non scheduleable
dynamic w2 = new JObject();
w2.name = Util.Uniquify("PatchConcurrencyViolationShouldFail");
w2.dollarAmount = 2.22m;
w2.active = true;
w2.roles = 0;
ApiResponse r2 = await Util.PostAsync("User", await Util.GetTokenAsync("manager", "l3tm3in"), w2.ToString());
Util.ValidateDataReturnResponseOk(r2);
long w2Id = r2.ObjectResponse["result"]["id"].Value<long>();
uint OriginalConcurrencyToken = r2.ObjectResponse["result"]["concurrencyToken"].Value<uint>();
ApiResponse R = await Util.PostAsync("User", await Util.GetTokenAsync("manager", "l3tm3in"), D.ToString());
Util.ValidateDataReturnResponseOk(R);
long w2Id = R.ObjectResponse["result"]["id"].Value<long>();
uint OriginalConcurrencyToken = R.ObjectResponse["result"]["concurrencyToken"].Value<uint>();
//PATCH