This commit is contained in:
@@ -44,15 +44,13 @@ namespace AyaNova.Api.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get full UserOptions object
|
/// Get full UserOptions object
|
||||||
///
|
///
|
||||||
/// Required roles:
|
/// Required roles:
|
||||||
/// BizAdminFull, InventoryFull, BizAdminLimited, InventoryLimited, TechFull, TechLimited, Accounting
|
/// BizAdminFull, BizAdminLimited or be users own record
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id"></param>
|
/// <param name="id">UserId</param>
|
||||||
/// <returns>A single UserOptions</returns>
|
/// <returns>A single UserOptions</returns>
|
||||||
[HttpGet("{id}")]
|
[HttpGet("{id}")]
|
||||||
public async Task<IActionResult> GetUserOptions([FromRoute] long id)
|
public async Task<IActionResult> GetUserOptions([FromRoute] long id)
|
||||||
@@ -62,7 +60,10 @@ namespace AyaNova.Api.Controllers
|
|||||||
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
|
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Authorized.IsAuthorizedToReadFullRecord(HttpContext.Items, AyaType.UserOptions))
|
var UserId = UserIdFromContext.Id(HttpContext.Items);
|
||||||
|
|
||||||
|
//Different than normal here: a user is *always* allowed to retrieve their own user options object
|
||||||
|
if (id != UserId && !Authorized.IsAuthorizedToReadFullRecord(HttpContext.Items, AyaType.UserOptions))
|
||||||
{
|
{
|
||||||
return StatusCode(401, new ApiNotAuthorizedResponse());
|
return StatusCode(401, new ApiNotAuthorizedResponse());
|
||||||
}
|
}
|
||||||
@@ -73,7 +74,7 @@ namespace AyaNova.Api.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Instantiate the business object handler
|
//Instantiate the business object handler
|
||||||
UserOptionsBiz biz = new UserOptionsBiz(ct, UserIdFromContext.Id(HttpContext.Items), UserRolesFromContext.Roles(HttpContext.Items));
|
UserOptionsBiz biz = new UserOptionsBiz(ct, UserId, UserRolesFromContext.Roles(HttpContext.Items));
|
||||||
|
|
||||||
var o = await biz.GetAsync(id);
|
var o = await biz.GetAsync(id);
|
||||||
|
|
||||||
@@ -82,92 +83,20 @@ namespace AyaNova.Api.Controllers
|
|||||||
return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
|
return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Log
|
|
||||||
EventLogProcessor.AddEntry(new Event(biz.userId, o.Id, AyaType.UserOptions, AyaEvent.Retrieved), ct);
|
|
||||||
ct.SaveChanges();
|
|
||||||
return Ok(new ApiOkResponse(o));
|
return Ok(new ApiOkResponse(o));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get paged list of UserOptionss
|
|
||||||
///
|
|
||||||
/// Required roles: Any
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Paged collection of UserOptionss with paging data</returns>
|
|
||||||
[HttpGet("ListUserOptionss", Name = nameof(ListUserOptionss))]//We MUST have a "Name" defined or we can't get the link for the pagination, non paged urls don't need a name
|
|
||||||
public async Task<IActionResult> ListUserOptionss([FromQuery] PagingOptions pagingOptions)
|
|
||||||
{
|
|
||||||
if (serverState.IsClosed)
|
|
||||||
{
|
|
||||||
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Authorized.IsAuthorizedToReadFullRecord(HttpContext.Items, AyaType.UserOptions))
|
|
||||||
{
|
|
||||||
return StatusCode(401, new ApiNotAuthorizedResponse());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
{
|
|
||||||
return BadRequest(new ApiErrorResponse(ModelState));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Instantiate the business object handler
|
|
||||||
UserOptionsBiz biz = new UserOptionsBiz(ct, UserIdFromContext.Id(HttpContext.Items), UserRolesFromContext.Roles(HttpContext.Items));
|
|
||||||
|
|
||||||
ApiPagedResponse<UserOptions> pr = await biz.GetManyAsync(Url, nameof(ListUserOptionss), pagingOptions);
|
|
||||||
return Ok(new ApiOkWithPagingResponse<UserOptions>(pr));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get UserOptions pick list
|
|
||||||
///
|
|
||||||
/// Required roles: Any
|
|
||||||
///
|
|
||||||
/// This list supports querying the Name property
|
|
||||||
/// include a "q" parameter for string to search for
|
|
||||||
/// use % for wildcards.
|
|
||||||
///
|
|
||||||
/// e.g. q=%Jones%
|
|
||||||
///
|
|
||||||
/// Query is case insensitive
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Paged id/name collection of UserOptionss with paging data</returns>
|
|
||||||
[HttpGet("PickList", Name = nameof(UserOptionsPickList))]
|
|
||||||
public async Task<IActionResult> UserOptionsPickList([FromQuery] string q, [FromQuery] PagingOptions pagingOptions)
|
|
||||||
{
|
|
||||||
if (serverState.IsClosed)
|
|
||||||
{
|
|
||||||
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
{
|
|
||||||
return BadRequest(new ApiErrorResponse(ModelState));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Instantiate the business object handler
|
|
||||||
UserOptionsBiz biz = new UserOptionsBiz(ct, UserIdFromContext.Id(HttpContext.Items), UserRolesFromContext.Roles(HttpContext.Items));
|
|
||||||
|
|
||||||
ApiPagedResponse<NameIdItem> pr = await biz.GetPickListAsync(Url, nameof(UserOptionsPickList), pagingOptions, q);
|
|
||||||
return Ok(new ApiOkWithPagingResponse<NameIdItem>(pr));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Put (update) UserOptions
|
/// Put (update) UserOptions
|
||||||
///
|
///
|
||||||
/// Required roles:
|
/// Required roles:
|
||||||
/// BizAdminFull, InventoryFull
|
/// BizAdminFull or be users own record
|
||||||
/// TechFull (owned only)
|
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id"></param>
|
/// <param name="id">User id</param>
|
||||||
/// <param name="inObj"></param>
|
/// <param name="inObj"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpPut("{id}")]
|
[HttpPut("{id}")]
|
||||||
@@ -182,15 +111,16 @@ namespace AyaNova.Api.Controllers
|
|||||||
{
|
{
|
||||||
return BadRequest(new ApiErrorResponse(ModelState));
|
return BadRequest(new ApiErrorResponse(ModelState));
|
||||||
}
|
}
|
||||||
|
var UserId = UserIdFromContext.Id(HttpContext.Items);
|
||||||
|
|
||||||
var o = await ct.UserOptions.SingleOrDefaultAsync(m => m.Id == id);
|
var o = await ct.UserOptions.SingleOrDefaultAsync(m => m.UserId == id);
|
||||||
|
|
||||||
if (o == null)
|
if (o == null)
|
||||||
{
|
{
|
||||||
return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
|
return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Authorized.IsAuthorizedToModify(HttpContext.Items, AyaType.UserOptions, o.OwnerId))
|
if (id != UserId && !Authorized.IsAuthorizedToModify(HttpContext.Items, AyaType.UserOptions, o.OwnerId))
|
||||||
{
|
{
|
||||||
return StatusCode(401, new ApiNotAuthorizedResponse());
|
return StatusCode(401, new ApiNotAuthorizedResponse());
|
||||||
}
|
}
|
||||||
@@ -218,14 +148,10 @@ namespace AyaNova.Api.Controllers
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
//exists but was changed by another user
|
//exists but was changed by another user
|
||||||
//I considered returning new and old record, but where would it end?
|
|
||||||
//Better to let the client decide what to do than to send extra data that is not required
|
|
||||||
return StatusCode(409, new ApiErrorResponse(ApiErrorCode.CONCURRENCY_CONFLICT));
|
return StatusCode(409, new ApiErrorResponse(ApiErrorCode.CONCURRENCY_CONFLICT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return Ok(new ApiOkResponse(new { ConcurrencyToken = o.ConcurrencyToken }));
|
return Ok(new ApiOkResponse(new { ConcurrencyToken = o.ConcurrencyToken }));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,17 +161,15 @@ namespace AyaNova.Api.Controllers
|
|||||||
/// Patch (update) UserOptions
|
/// Patch (update) UserOptions
|
||||||
///
|
///
|
||||||
/// Required roles:
|
/// Required roles:
|
||||||
/// BizAdminFull, InventoryFull
|
/// BizAdminFull or be users own record
|
||||||
/// TechFull (owned only)
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id"></param>
|
/// <param name="id">UserId</param>
|
||||||
/// <param name="concurrencyToken"></param>
|
/// <param name="concurrencyToken"></param>
|
||||||
/// <param name="objectPatch"></param>
|
/// <param name="objectPatch"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpPatch("{id}/{concurrencyToken}")]
|
[HttpPatch("{id}/{concurrencyToken}")]
|
||||||
public async Task<IActionResult> PatchUserOptions([FromRoute] long id, [FromRoute] uint concurrencyToken, [FromBody]JsonPatchDocument<UserOptions> objectPatch)
|
public async Task<IActionResult> PatchUserOptions([FromRoute] long id, [FromRoute] uint concurrencyToken, [FromBody]JsonPatchDocument<UserOptions> objectPatch)
|
||||||
{
|
{
|
||||||
//https://dotnetcoretutorials.com/2017/11/29/json-patch-asp-net-core/
|
|
||||||
|
|
||||||
if (!serverState.IsOpen)
|
if (!serverState.IsOpen)
|
||||||
{
|
{
|
||||||
@@ -257,18 +181,19 @@ namespace AyaNova.Api.Controllers
|
|||||||
return BadRequest(new ApiErrorResponse(ModelState));
|
return BadRequest(new ApiErrorResponse(ModelState));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var UserId = UserIdFromContext.Id(HttpContext.Items);
|
||||||
|
|
||||||
//Instantiate the business object handler
|
//Instantiate the business object handler
|
||||||
UserOptionsBiz biz = new UserOptionsBiz(ct, UserIdFromContext.Id(HttpContext.Items), UserRolesFromContext.Roles(HttpContext.Items));
|
UserOptionsBiz biz = new UserOptionsBiz(ct, UserId, UserRolesFromContext.Roles(HttpContext.Items));
|
||||||
|
|
||||||
|
var o = await ct.UserOptions.SingleOrDefaultAsync(m => m.UserId == id);
|
||||||
var o = await ct.UserOptions.SingleOrDefaultAsync(m => m.Id == id);
|
|
||||||
|
|
||||||
if (o == null)
|
if (o == null)
|
||||||
{
|
{
|
||||||
return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
|
return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Authorized.IsAuthorizedToModify(HttpContext.Items, AyaType.UserOptions, o.OwnerId))
|
if (id != UserId && !Authorized.IsAuthorizedToModify(HttpContext.Items, AyaType.UserOptions, o.OwnerId))
|
||||||
{
|
{
|
||||||
return StatusCode(401, new ApiNotAuthorizedResponse());
|
return StatusCode(401, new ApiNotAuthorizedResponse());
|
||||||
}
|
}
|
||||||
@@ -297,197 +222,18 @@ namespace AyaNova.Api.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return Ok(new ApiOkResponse(new { ConcurrencyToken = o.ConcurrencyToken }));
|
return Ok(new ApiOkResponse(new { ConcurrencyToken = o.ConcurrencyToken }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Post UserOptions
|
|
||||||
///
|
|
||||||
/// Required roles:
|
|
||||||
/// BizAdminFull, InventoryFull, TechFull
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inObj"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<IActionResult> PostUserOptions([FromBody] UserOptions inObj)
|
|
||||||
{
|
|
||||||
if (!serverState.IsOpen)
|
|
||||||
{
|
|
||||||
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
|
|
||||||
}
|
|
||||||
|
|
||||||
//If a user has change roles, or editOwnRoles then they can create, true is passed for isOwner since they are creating so by definition the owner
|
|
||||||
if (!Authorized.IsAuthorizedToCreate(HttpContext.Items, AyaType.UserOptions))
|
|
||||||
{
|
|
||||||
return StatusCode(401, new ApiNotAuthorizedResponse());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
{
|
|
||||||
return BadRequest(new ApiErrorResponse(ModelState));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Instantiate the business object handler
|
|
||||||
UserOptionsBiz biz = new UserOptionsBiz(ct, UserIdFromContext.Id(HttpContext.Items), UserRolesFromContext.Roles(HttpContext.Items));
|
|
||||||
|
|
||||||
//Create and validate
|
|
||||||
UserOptions o = await biz.CreateAsync(inObj);
|
|
||||||
|
|
||||||
if (o == null)
|
|
||||||
{
|
|
||||||
//error return
|
|
||||||
return BadRequest(new ApiErrorResponse(biz.Errors));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
//save to get Id
|
|
||||||
await ct.SaveChangesAsync();
|
|
||||||
|
|
||||||
//Log now that we have the Id
|
|
||||||
EventLogProcessor.AddEntry(new Event(biz.userId, o.Id, AyaType.UserOptions, AyaEvent.Created), ct);
|
|
||||||
await ct.SaveChangesAsync();
|
|
||||||
|
|
||||||
//return success and link
|
|
||||||
return CreatedAtAction("GetUserOptions", new { id = o.Id }, new ApiCreatedResponse(o));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Delete UserOptions
|
|
||||||
///
|
|
||||||
/// Required roles:
|
|
||||||
/// BizAdminFull, InventoryFull
|
|
||||||
/// TechFull (owned only)
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id"></param>
|
|
||||||
/// <returns>Ok</returns>
|
|
||||||
[HttpDelete("{id}")]
|
|
||||||
public async Task<IActionResult> DeleteUserOptions([FromRoute] long id)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!serverState.IsOpen)
|
|
||||||
{
|
|
||||||
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
{
|
|
||||||
return BadRequest(new ApiErrorResponse(ModelState));
|
|
||||||
}
|
|
||||||
|
|
||||||
var dbObj = await ct.UserOptions.SingleOrDefaultAsync(m => m.Id == id);
|
|
||||||
if (dbObj == null)
|
|
||||||
{
|
|
||||||
return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Authorized.IsAuthorizedToDelete(HttpContext.Items, AyaType.UserOptions, dbObj.OwnerId))
|
|
||||||
{
|
|
||||||
return StatusCode(401, new ApiNotAuthorizedResponse());
|
|
||||||
}
|
|
||||||
|
|
||||||
//Instantiate the business object handler
|
|
||||||
UserOptionsBiz biz = new UserOptionsBiz(ct, UserIdFromContext.Id(HttpContext.Items), UserRolesFromContext.Roles(HttpContext.Items));
|
|
||||||
if (!biz.Delete(dbObj))
|
|
||||||
{
|
|
||||||
return BadRequest(new ApiErrorResponse(biz.Errors));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Log
|
|
||||||
EventLogProcessor.DeleteObject(biz.userId, AyaType.UserOptions, dbObj.Id, dbObj.Name, ct);
|
|
||||||
|
|
||||||
await ct.SaveChangesAsync();
|
|
||||||
|
|
||||||
//Delete children / attached objects
|
|
||||||
biz.DeleteChildren(dbObj);
|
|
||||||
|
|
||||||
|
|
||||||
return NoContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private bool UserOptionsExists(long id)
|
private bool UserOptionsExists(long id)
|
||||||
{
|
{
|
||||||
return ct.UserOptions.Any(e => e.Id == id);
|
//NOTE: checks by UserId, NOT by Id as in most other objects
|
||||||
|
return ct.UserOptions.Any(e => e.UserId == id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get route that triggers exception for testing
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Nothing, triggers exception</returns>
|
|
||||||
[HttpGet("exception")]
|
|
||||||
public ActionResult GetException()
|
|
||||||
{
|
|
||||||
if (!serverState.IsOpen)
|
|
||||||
{
|
|
||||||
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Authorized.IsAuthorizedToReadFullRecord(HttpContext.Items, AyaType.UserOptions))
|
|
||||||
{
|
|
||||||
return StatusCode(401, new ApiNotAuthorizedResponse());
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new System.NotSupportedException("Test exception from UserOptions controller");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get route that triggers an alternate type of exception for testing
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Nothing, triggers exception</returns>
|
|
||||||
[HttpGet("altexception")]
|
|
||||||
public ActionResult GetAltException()
|
|
||||||
{
|
|
||||||
if (!serverState.IsOpen)
|
|
||||||
{
|
|
||||||
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Authorized.IsAuthorizedToReadFullRecord(HttpContext.Items, AyaType.UserOptions))
|
|
||||||
{
|
|
||||||
return StatusCode(401, new ApiNotAuthorizedResponse());
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new System.ArgumentException("Test exception (ALT) from UserOptions controller");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get route that submits a simulated long running operation job for testing
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Nothing</returns>
|
|
||||||
[HttpGet("TestUserOptionsJob")]
|
|
||||||
public ActionResult TestUserOptionsJob()
|
|
||||||
{
|
|
||||||
if (!serverState.IsOpen)
|
|
||||||
{
|
|
||||||
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Authorized.IsAuthorizedToModify(HttpContext.Items, AyaType.JobOperations))
|
|
||||||
{
|
|
||||||
return StatusCode(401, new ApiNotAuthorizedResponse());
|
|
||||||
}
|
|
||||||
|
|
||||||
//Create the job here
|
|
||||||
OpsJob j = new OpsJob();
|
|
||||||
j.Name = "TestUserOptionsJob";
|
|
||||||
j.JobType = JobType.TestUserOptionsJob;
|
|
||||||
JobsBiz.AddJob(j, ct);
|
|
||||||
return Accepted(new { JobId = j.GId });//202 accepted
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------
|
//------------
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ namespace AyaNova.Biz
|
|||||||
AyaNova7Import = 10,
|
AyaNova7Import = 10,
|
||||||
TrialSeeder = 11,
|
TrialSeeder = 11,
|
||||||
Metrics = 12,
|
Metrics = 12,
|
||||||
Locale = 13
|
Locale = 13,
|
||||||
|
UserOptions=14
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace AyaNova.Biz
|
|||||||
//CHANGE = CREATE, RETRIEVE, UPDATE, DELETE - Full rights
|
//CHANGE = CREATE, RETRIEVE, UPDATE, DELETE - Full rights
|
||||||
//EDITOWN = special subset of CHANGE: You can create and if it's one you created then you have rights to edit it or delete, but you can't edit ones others have created
|
//EDITOWN = special subset of CHANGE: You can create and if it's one you created then you have rights to edit it or delete, but you can't edit ones others have created
|
||||||
//READ = You can read *all* the fields of the record, but can't modify it. Change is automatically checked for so only add different roles from change
|
//READ = You can read *all* the fields of the record, but can't modify it. Change is automatically checked for so only add different roles from change
|
||||||
//PICKLIST NOTE: this does not control getting a list of names for selection which is role independent because it's required for so much indirectly
|
//PICKLIST NOTE: this does not control getting a list of names for selection which is role independent because it's required for so much indirectly
|
||||||
//DELETE = There is no specific delete right for now though it's checked for by routes in Authorized.cs in case we want to add it in future as a separate right from create.
|
//DELETE = There is no specific delete right for now though it's checked for by routes in Authorized.cs in case we want to add it in future as a separate right from create.
|
||||||
|
|
||||||
#region All roles initialization
|
#region All roles initialization
|
||||||
@@ -38,6 +38,19 @@ namespace AyaNova.Biz
|
|||||||
ReadFullRecord = AuthorizationRoles.BizAdminLimited
|
ReadFullRecord = AuthorizationRoles.BizAdminLimited
|
||||||
});
|
});
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//USEROPTIONS
|
||||||
|
//(Identical to User, though route also allows own record access full changes)
|
||||||
|
//
|
||||||
|
roles.Add(AyaType.UserOptions, new BizRoleSet()
|
||||||
|
{
|
||||||
|
Change = AuthorizationRoles.BizAdminFull,
|
||||||
|
EditOwn = AuthorizationRoles.NoRole,//no one can make a user but a bizadminfull
|
||||||
|
ReadFullRecord = AuthorizationRoles.BizAdminLimited
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//WIDGET
|
//WIDGET
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -35,8 +35,9 @@ namespace AyaNova.Biz
|
|||||||
//Get one
|
//Get one
|
||||||
internal async Task<UserOptions> GetAsync(long fetchId)
|
internal async Task<UserOptions> GetAsync(long fetchId)
|
||||||
{
|
{
|
||||||
|
//NOTE: get by UserId as there is a 1:1 relationship, not by useroptions id
|
||||||
//This is simple so nothing more here, but often will be copying to a different output object or some other ops
|
//This is simple so nothing more here, but often will be copying to a different output object or some other ops
|
||||||
return await ct.UserOptions.SingleOrDefaultAsync(m => m.Id == fetchId);
|
return await ct.UserOptions.SingleOrDefaultAsync(m => m.UserId == fetchId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ namespace AyaNova.Biz
|
|||||||
{
|
{
|
||||||
|
|
||||||
//Replace the db object with the PUT object
|
//Replace the db object with the PUT object
|
||||||
CopyObject.Copy(inObj, dbObj, "Id");
|
CopyObject.Copy(inObj, dbObj, "Id, UserId, OwnerId");
|
||||||
//Set "original" value of concurrency token to input token
|
//Set "original" value of concurrency token to input token
|
||||||
//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;
|
||||||
@@ -65,7 +66,7 @@ namespace AyaNova.Biz
|
|||||||
internal bool Patch(UserOptions dbObj, JsonPatchDocument<UserOptions> objectPatch, uint concurrencyToken)
|
internal bool Patch(UserOptions dbObj, JsonPatchDocument<UserOptions> objectPatch, uint concurrencyToken)
|
||||||
{
|
{
|
||||||
//Validate Patch is allowed
|
//Validate Patch is allowed
|
||||||
if (!ValidateJsonPatch<UserOptions>.Validate(this, objectPatch)) return false;
|
if (!ValidateJsonPatch<UserOptions>.Validate(this, objectPatch, "UserId")) return false;
|
||||||
|
|
||||||
//Do the patching
|
//Do the patching
|
||||||
objectPatch.ApplyTo(dbObj);
|
objectPatch.ApplyTo(dbObj);
|
||||||
|
|||||||
131
test/raven-integration/User/UserOptionsRu.cs
Normal file
131
test/raven-integration/User/UserOptionsRu.cs
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
using System;
|
||||||
|
using Xunit;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using FluentAssertions;
|
||||||
|
|
||||||
|
namespace raven_integration
|
||||||
|
{
|
||||||
|
|
||||||
|
public class UserOptionsRu
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test all CRUD routes for a UserOptions object
|
||||||
|
/// </summary>
|
||||||
|
[Fact]
|
||||||
|
public async void RU()
|
||||||
|
{
|
||||||
|
|
||||||
|
//CREATE a user
|
||||||
|
dynamic D1 = new JObject();
|
||||||
|
D1.name = Util.Uniquify("Test UserOptions 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 R = await Util.PostAsync("User", await Util.GetTokenAsync("manager", "l3tm3in"), D1.ToString());
|
||||||
|
Util.ValidateDataReturnResponseOk(R);
|
||||||
|
long UserId = R.ObjectResponse["result"]["id"].Value<long>();
|
||||||
|
|
||||||
|
//Now there should be a user options available for this user
|
||||||
|
|
||||||
|
|
||||||
|
//RETRIEVE companion USEROPTIONS object
|
||||||
|
|
||||||
|
//Get it
|
||||||
|
R = await Util.GetAsync("UserOptions/" + UserId.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"));
|
||||||
|
Util.ValidateDataReturnResponseOk(R);
|
||||||
|
//ensure the default value is set
|
||||||
|
R.ObjectResponse["result"]["uiColor"].Value<int>().Should().Be(0);
|
||||||
|
uint concurrencyToken = R.ObjectResponse["result"]["concurrencyToken"].Value<uint>();
|
||||||
|
|
||||||
|
//UPDATE
|
||||||
|
//PUT
|
||||||
|
dynamic D2 = new JObject();
|
||||||
|
D2.emailaddress = "testuseroptions@helloayanova.com";
|
||||||
|
D2.TimeZoneOffset = -7.5M;//Decimal value
|
||||||
|
D2.UiColor = -2097216;//Int value (no suffix for int literals)
|
||||||
|
D2.concurrencyToken = concurrencyToken;
|
||||||
|
ApiResponse PUTTestResponse = await Util.PutAsync("UserOptions/" + UserId.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"), D2.ToString());
|
||||||
|
Util.ValidateHTTPStatusCode(PUTTestResponse, 200);
|
||||||
|
|
||||||
|
//VALIDATE
|
||||||
|
R = await Util.GetAsync("UserOptions/" + UserId.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"));
|
||||||
|
Util.ValidateDataReturnResponseOk(R);
|
||||||
|
//ensure the default value is set
|
||||||
|
R.ObjectResponse["result"]["emailAddress"].Value<string>().Should().Be(D2.emailaddress.ToString());
|
||||||
|
R.ObjectResponse["result"]["timeZoneOffset"].Value<decimal>().Should().Be((decimal)D2.TimeZoneOffset);
|
||||||
|
R.ObjectResponse["result"]["uiColor"].Value<int>().Should().Be((int)D2.UiColor);
|
||||||
|
concurrencyToken = R.ObjectResponse["result"]["concurrencyToken"].Value<uint>();
|
||||||
|
|
||||||
|
// //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());
|
||||||
|
// 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());
|
||||||
|
// uint concurrencyToken = PUTTestResponse.ObjectResponse["result"]["concurrencyToken"].Value<uint>();
|
||||||
|
|
||||||
|
// //PATCH
|
||||||
|
// var newName = Util.Uniquify("UPDATED VIA PATCH SECOND TEST User");
|
||||||
|
// string patchJson = "[{\"value\": \"" + newName + "\",\"path\": \"/name\",\"op\": \"replace\"}]";
|
||||||
|
// ApiResponse PATCHTestResponse = await Util.PatchAsync("User/" + d2Id.ToString() + "/" + concurrencyToken.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"), patchJson);
|
||||||
|
// Util.ValidateHTTPStatusCode(PATCHTestResponse, 200);
|
||||||
|
|
||||||
|
// //check PATCH worked
|
||||||
|
// ApiResponse checkPATCHWorked = await Util.GetAsync("User/" + d2Id.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"));
|
||||||
|
// Util.ValidateNoErrorInResponse(checkPATCHWorked);
|
||||||
|
// checkPATCHWorked.ObjectResponse["result"]["name"].Value<string>().Should().Be(newName);
|
||||||
|
|
||||||
|
// //DELETE
|
||||||
|
// ApiResponse DELETETestResponse = await Util.DeleteAsync("User/" + d2Id.ToString(), await Util.GetTokenAsync("manager", "l3tm3in"));
|
||||||
|
// Util.ValidateHTTPStatusCode(DELETETestResponse, 204);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test not found
|
||||||
|
/// </summary>
|
||||||
|
[Fact]
|
||||||
|
public async void GetNonExistentItemShouldError()
|
||||||
|
{
|
||||||
|
//Get non existant
|
||||||
|
//Should return status code 404, api error code 2010
|
||||||
|
ApiResponse R = await Util.GetAsync("UserOptions/999999", await Util.GetTokenAsync("manager", "l3tm3in"));
|
||||||
|
Util.ValidateResponseNotFound(R);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test bad modelstate
|
||||||
|
/// </summary>
|
||||||
|
[Fact]
|
||||||
|
public async void GetBadModelStateShouldError()
|
||||||
|
{
|
||||||
|
//Get non existant
|
||||||
|
//Should return status code 400, api error code 2200 and a first target in details of "id"
|
||||||
|
ApiResponse R = await Util.GetAsync("UserOptions/2q2", await Util.GetTokenAsync("manager", "l3tm3in"));
|
||||||
|
Util.ValidateBadModelStateResponse(R, "id");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==================================================
|
||||||
|
|
||||||
|
}//eoc
|
||||||
|
}//eons
|
||||||
Reference in New Issue
Block a user