This commit is contained in:
@@ -153,19 +153,24 @@ namespace AyaNova.Biz
|
|||||||
//put
|
//put
|
||||||
internal bool Put(User dbObj, User inObj)
|
internal bool Put(User dbObj, User inObj)
|
||||||
{
|
{
|
||||||
//Replace the db object with the PUT object skipping the password and salt and Id fields
|
//Get a snapshot of the original db value object before changes
|
||||||
CopyObject.Copy(inObj, dbObj, "Id, Salt, Password");
|
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?
|
//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:
|
//YES password is being updated:
|
||||||
inObj.Password = Hasher.hash(inObj.Salt, inObj.Password);
|
dbObj.Password = Hasher.hash(SnapshotObj.Salt, inObj.Password);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//No, use the db password value
|
//No, use the snapshot password value
|
||||||
//Should not require any code to run as it will retain it's db value
|
dbObj.Password = SnapshotObj.Password;
|
||||||
|
dbObj.Salt = SnapshotObj.Salt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -173,7 +178,7 @@ namespace AyaNova.Biz
|
|||||||
//this will allow EF to check it out
|
//this will allow EF to check it out
|
||||||
ct.Entry(dbObj).OriginalValues["ConcurrencyToken"] = inObj.ConcurrencyToken;
|
ct.Entry(dbObj).OriginalValues["ConcurrencyToken"] = inObj.ConcurrencyToken;
|
||||||
|
|
||||||
Validate(dbObj, inObj);
|
Validate(dbObj, SnapshotObj);
|
||||||
if (HasErrors)
|
if (HasErrors)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -183,15 +188,20 @@ namespace AyaNova.Biz
|
|||||||
//patch
|
//patch
|
||||||
internal bool Patch(User dbObj, JsonPatchDocument<User> objectPatch, uint concurrencyToken)
|
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 = new User();
|
||||||
//make a snapshot of the original for validation but update the original to preserve workflow
|
|
||||||
|
|
||||||
User snapshotObj=null;
|
|
||||||
CopyObject.Copy(dbObj, snapshotObj);
|
CopyObject.Copy(dbObj, snapshotObj);
|
||||||
|
|
||||||
//Do the patching
|
//Do the patching
|
||||||
objectPatch.ApplyTo(dbObj);
|
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;
|
ct.Entry(dbObj).OriginalValues["ConcurrencyToken"] = concurrencyToken;
|
||||||
Validate(dbObj, snapshotObj);
|
Validate(dbObj, snapshotObj);
|
||||||
if (HasErrors)
|
if (HasErrors)
|
||||||
@@ -237,7 +247,7 @@ namespace AyaNova.Biz
|
|||||||
//run validation and biz rules
|
//run validation and biz rules
|
||||||
bool isNew = currentObj == null;
|
bool isNew = currentObj == null;
|
||||||
|
|
||||||
|
|
||||||
if (isNew) //Yes, no currentObj
|
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?
|
//Not sure why we would care about this particular rule or why I added it? Maybe it's from widget?
|
||||||
|
|||||||
@@ -22,7 +22,10 @@ namespace AyaNova.Util
|
|||||||
{
|
{
|
||||||
string[] excluded = null;
|
string[] excluded = null;
|
||||||
if (!string.IsNullOrEmpty(excludedProperties))
|
if (!string.IsNullOrEmpty(excludedProperties))
|
||||||
|
{
|
||||||
|
excludedProperties=excludedProperties.Replace(", ", ",").Replace(" ,",",").Trim();
|
||||||
excluded = excludedProperties.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
excluded = excludedProperties.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
}
|
||||||
|
|
||||||
MemberInfo[] miT = target.GetType().GetMembers(memberAccess);
|
MemberInfo[] miT = target.GetType().GetMembers(memberAccess);
|
||||||
foreach (MemberInfo Field in miT)
|
foreach (MemberInfo Field in miT)
|
||||||
|
|||||||
@@ -15,44 +15,44 @@ namespace raven_integration
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async void CRUD()
|
public async void CRUD()
|
||||||
{
|
{
|
||||||
|
|
||||||
//CREATE
|
//CREATE
|
||||||
dynamic d1 = new JObject();
|
dynamic D1 = new JObject();
|
||||||
d1.name = Util.Uniquify("First Test User");
|
D1.name = Util.Uniquify("First Test User");
|
||||||
d1.ownerId = 1L;
|
D1.ownerId = 1L;
|
||||||
d1.active=true;
|
D1.active = true;
|
||||||
d1.login=Util.Uniquify("LOGIN");
|
D1.login = Util.Uniquify("LOGIN");
|
||||||
d1.password=Util.Uniquify("PASSWORD");
|
D1.password = Util.Uniquify("PASSWORD");
|
||||||
d1.roles=0;//norole
|
D1.roles = 0;//norole
|
||||||
d1.localeId=1;//random locale
|
D1.localeId = 1;//random locale
|
||||||
d1.userType=3;//non scheduleable
|
D1.userType = 3;//non scheduleable
|
||||||
|
|
||||||
ApiResponse r1 = await Util.PostAsync("User", await Util.GetTokenAsync("manager", "l3tm3in"), d1.ToString());
|
ApiResponse R1 = await Util.PostAsync("User", await Util.GetTokenAsync("manager", "l3tm3in"), D1.ToString());
|
||||||
Util.ValidateDataReturnResponseOk(r1);
|
Util.ValidateDataReturnResponseOk(R1);
|
||||||
long d1Id = r1.ObjectResponse["result"]["id"].Value<long>();
|
long d1Id = R1.ObjectResponse["result"]["id"].Value<long>();
|
||||||
|
|
||||||
|
|
||||||
dynamic d2 = new JObject();
|
dynamic D2 = new JObject();
|
||||||
d2.name = Util.Uniquify("Second Test User");
|
D2.name = Util.Uniquify("Second Test User");
|
||||||
d2.ownerId = 1L;
|
D2.ownerId = 1L;
|
||||||
d2.active=true;
|
D2.active = true;
|
||||||
d2.login=Util.Uniquify("LOGIN");
|
D2.login = Util.Uniquify("LOGIN");
|
||||||
d2.password=Util.Uniquify("PASSWORD");
|
D2.password = Util.Uniquify("PASSWORD");
|
||||||
d2.roles=0;//norole
|
D2.roles = 0;//norole
|
||||||
d2.localeId=1;//random locale
|
D2.localeId = 1;//random locale
|
||||||
d2.userType=3;//non scheduleable
|
D2.userType = 3;//non scheduleable
|
||||||
|
|
||||||
ApiResponse r2 = await Util.PostAsync("User", await Util.GetTokenAsync("manager", "l3tm3in"), d2.ToString());
|
ApiResponse R2 = await Util.PostAsync("User", await Util.GetTokenAsync("manager", "l3tm3in"), D2.ToString());
|
||||||
Util.ValidateDataReturnResponseOk(r2);
|
Util.ValidateDataReturnResponseOk(R2);
|
||||||
long d2Id = r2.ObjectResponse["result"]["id"].Value<long>();
|
long d2Id = R2.ObjectResponse["result"]["id"].Value<long>();
|
||||||
|
|
||||||
|
|
||||||
//RETRIEVE
|
//RETRIEVE
|
||||||
|
|
||||||
//Get one
|
//Get one
|
||||||
ApiResponse r3 = await Util.GetAsync("User/" + d2Id.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"));
|
ApiResponse R3 = await Util.GetAsync("User/" + d2Id.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"));
|
||||||
Util.ValidateDataReturnResponseOk(r3);
|
Util.ValidateDataReturnResponseOk(R3);
|
||||||
r3.ObjectResponse["result"]["name"].Value<string>().Should().Be(d2.name.ToString());
|
R3.ObjectResponse["result"]["name"].Value<string>().Should().Be(D2.name.ToString());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -60,16 +60,16 @@ namespace raven_integration
|
|||||||
//PUT
|
//PUT
|
||||||
|
|
||||||
//update w2id
|
//update w2id
|
||||||
d2.name = Util.Uniquify("UPDATED VIA PUT SECOND TEST User");
|
D2.name = Util.Uniquify("UPDATED VIA PUT SECOND TEST User");
|
||||||
d2.OwnerId = 1;
|
D2.OwnerId = 1;
|
||||||
d2.concurrencyToken = r2.ObjectResponse["result"]["concurrencyToken"].Value<uint>();
|
D2.concurrencyToken = R2.ObjectResponse["result"]["concurrencyToken"].Value<uint>();
|
||||||
ApiResponse PUTTestResponse = await Util.PutAsync("User/" + d2Id.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"), d2.ToString());
|
ApiResponse PUTTestResponse = await Util.PutAsync("User/" + d2Id.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"), D2.ToString());
|
||||||
Util.ValidateHTTPStatusCode(PUTTestResponse, 200);
|
Util.ValidateHTTPStatusCode(PUTTestResponse, 200);
|
||||||
|
|
||||||
//check PUT worked
|
//check PUT worked
|
||||||
ApiResponse checkPUTWorked = await Util.GetAsync("User/" + d2Id.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"));
|
ApiResponse checkPUTWorked = await Util.GetAsync("User/" + d2Id.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"));
|
||||||
Util.ValidateNoErrorInResponse(checkPUTWorked);
|
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>();
|
uint concurrencyToken = PUTTestResponse.ObjectResponse["result"]["concurrencyToken"].Value<uint>();
|
||||||
|
|
||||||
//PATCH
|
//PATCH
|
||||||
@@ -89,7 +89,7 @@ namespace raven_integration
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//TODO: Test password updating code
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -101,8 +101,8 @@ namespace raven_integration
|
|||||||
{
|
{
|
||||||
//Get non existant
|
//Get non existant
|
||||||
//Should return status code 404, api error code 2010
|
//Should return status code 404, api error code 2010
|
||||||
ApiResponse a = await Util.GetAsync("User/999999", await Util.GetTokenAsync("manager", "l3tm3in"));
|
ApiResponse R = await Util.GetAsync("User/999999", await Util.GetTokenAsync("manager", "l3tm3in"));
|
||||||
Util.ValidateResponseNotFound(a);
|
Util.ValidateResponseNotFound(R);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -113,8 +113,8 @@ namespace raven_integration
|
|||||||
{
|
{
|
||||||
//Get non existant
|
//Get non existant
|
||||||
//Should return status code 400, api error code 2200 and a first target in details of "id"
|
//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"));
|
ApiResponse R = await Util.GetAsync("User/2q2", await Util.GetTokenAsync("manager", "l3tm3in"));
|
||||||
Util.ValidateBadModelStateResponse(a, "id");
|
Util.ValidateBadModelStateResponse(R, "id");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -128,29 +128,29 @@ namespace raven_integration
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async void PutConcurrencyViolationShouldFail()
|
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
|
ApiResponse R = await Util.PostAsync("User", await Util.GetTokenAsync("manager", "l3tm3in"), D.ToString());
|
||||||
|
Util.ValidateDataReturnResponseOk(R);
|
||||||
dynamic w2 = new JObject();
|
long D1Id = R.ObjectResponse["result"]["id"].Value<long>();
|
||||||
w2.name = Util.Uniquify("PutConcurrencyViolationShouldFail");
|
uint OriginalConcurrencyToken = R.ObjectResponse["result"]["concurrencyToken"].Value<uint>();
|
||||||
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>();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//UPDATE
|
//UPDATE
|
||||||
//PUT
|
//PUT
|
||||||
|
|
||||||
w2.name = Util.Uniquify("PutConcurrencyViolationShouldFail UPDATE VIA PUT ");
|
D.name = Util.Uniquify("PutConcurrencyViolationShouldFail UPDATE VIA PUT ");
|
||||||
w2.OwnerId = 1;
|
D.concurrencyToken = OriginalConcurrencyToken - 1;//bad token
|
||||||
w2.concurrencyToken = OriginalConcurrencyToken - 1;//bad token
|
ApiResponse PUTTestResponse = await Util.PutAsync("User/" + D1Id.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"), D.ToString());
|
||||||
ApiResponse PUTTestResponse = await Util.PutAsync("User/" + w2Id.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"), w2.ToString());
|
|
||||||
Util.ValidateConcurrencyError(PUTTestResponse);
|
Util.ValidateConcurrencyError(PUTTestResponse);
|
||||||
|
|
||||||
|
|
||||||
@@ -165,19 +165,21 @@ namespace raven_integration
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async void PatchConcurrencyViolationShouldFail()
|
public async void PatchConcurrencyViolationShouldFail()
|
||||||
{
|
{
|
||||||
|
|
||||||
//CREATE
|
//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();
|
ApiResponse R = await Util.PostAsync("User", await Util.GetTokenAsync("manager", "l3tm3in"), D.ToString());
|
||||||
w2.name = Util.Uniquify("PatchConcurrencyViolationShouldFail");
|
Util.ValidateDataReturnResponseOk(R);
|
||||||
w2.dollarAmount = 2.22m;
|
long w2Id = R.ObjectResponse["result"]["id"].Value<long>();
|
||||||
w2.active = true;
|
uint OriginalConcurrencyToken = R.ObjectResponse["result"]["concurrencyToken"].Value<uint>();
|
||||||
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>();
|
|
||||||
|
|
||||||
|
|
||||||
//PATCH
|
//PATCH
|
||||||
|
|||||||
Reference in New Issue
Block a user