From dfad4c948e13a447ad357c42f101186c5242c928 Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Thu, 4 Oct 2018 18:49:46 +0000 Subject: [PATCH] --- server/AyaNova/Controllers/TagController.cs | 222 ++++-------------- .../AyaNova/Controllers/WidgetController.cs | 1 - server/AyaNova/biz/BizObjectFactory.cs | 2 +- server/AyaNova/biz/TagBiz.cs | 72 +++++- server/AyaNova/biz/WidgetBiz.cs | 2 + 5 files changed, 112 insertions(+), 187 deletions(-) diff --git a/server/AyaNova/Controllers/TagController.cs b/server/AyaNova/Controllers/TagController.cs index 21b3d643..8f2bdaec 100644 --- a/server/AyaNova/Controllers/TagController.cs +++ b/server/AyaNova/Controllers/TagController.cs @@ -55,29 +55,20 @@ namespace AyaNova.Api.Controllers public async Task GetTag([FromRoute] long id) { if (!serverState.IsOpen) - { return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason)); - } - - if (!Authorized.IsAuthorizedToReadFullRecord(HttpContext.Items, AyaType.Tag)) - { - return StatusCode(401, new ApiNotAuthorizedResponse()); - } - - if (!ModelState.IsValid) - { - return BadRequest(new ApiErrorResponse(ModelState)); - } //Instantiate the business object handler - TagBiz biz = new TagBiz(ct, UserIdFromContext.Id(HttpContext.Items), UserRolesFromContext.Roles(HttpContext.Items)); + TagBiz biz = TagBiz.GetBiz(ct, HttpContext); + + if (!Authorized.IsAuthorizedToReadFullRecord(HttpContext.Items, biz.BizType)) + return StatusCode(401, new ApiNotAuthorizedResponse()); + + if (!ModelState.IsValid) + return BadRequest(new ApiErrorResponse(ModelState)); var o = await biz.GetAsync(id); - if (o == null) - { return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); - } return Ok(new ApiOkResponse(o)); } @@ -103,22 +94,16 @@ namespace AyaNova.Api.Controllers public async Task PickList([FromQuery] string q, [FromQuery] PagingOptions pagingOptions) { if (!serverState.IsOpen) - { return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason)); - } - - if (!Authorized.IsAuthorizedToReadFullRecord(HttpContext.Items, AyaType.Tag))//Note: anyone can read a tag, but that might change in future so keeping this code in - { - return StatusCode(401, new ApiNotAuthorizedResponse()); - } - - if (!ModelState.IsValid) - { - return BadRequest(new ApiErrorResponse(ModelState)); - } //Instantiate the business object handler - TagBiz biz = new TagBiz(ct, UserIdFromContext.Id(HttpContext.Items), UserRolesFromContext.Roles(HttpContext.Items)); + TagBiz biz = TagBiz.GetBiz(ct, HttpContext); + + if (!Authorized.IsAuthorizedToReadFullRecord(HttpContext.Items, biz.BizType))//Note: anyone can read a tag, but that might change in future so keeping this code in + return StatusCode(401, new ApiNotAuthorizedResponse()); + + if (!ModelState.IsValid) + return BadRequest(new ApiErrorResponse(ModelState)); ApiPagedResponse pr = await biz.GetPickListAsync(Url, nameof(PickList), pagingOptions, q); return Ok(new ApiOkWithPagingResponse(pr)); @@ -137,49 +122,27 @@ namespace AyaNova.Api.Controllers public async Task PostTag([FromBody] NameItem inObj) { if (!serverState.IsOpen) - { return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason)); - } //Instantiate the business object handler - TagBiz biz = new TagBiz(ct, UserIdFromContext.Id(HttpContext.Items), UserRolesFromContext.Roles(HttpContext.Items)); + TagBiz biz = TagBiz.GetBiz(ct, HttpContext); //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, biz.BizType)) - { return StatusCode(401, new ApiNotAuthorizedResponse()); - } if (!ModelState.IsValid) - { return BadRequest(new ApiErrorResponse(ModelState)); - } - - //Create and validate Tag o = await biz.CreateAsync(inObj.Name); - if (o == null) - { - //error return return BadRequest(new ApiErrorResponse(biz.Errors)); - } else - { - //save and get ID for log then success return - await ct.SaveChangesAsync(); - - //Log - EventLogProcessor.AddEntryToContextNoSave(new Event(biz.UserId, o.Id, AyaType.Tag, AyaEvent.Created), ct); - await ct.SaveChangesAsync(); - return CreatedAtAction("GetTag", new { id = o.Id }, new ApiCreatedResponse(o)); - } } - /// /// Put (update) Tag /// @@ -194,58 +157,33 @@ namespace AyaNova.Api.Controllers public async Task PutTag([FromRoute] long id, [FromBody] Tag oIn) { if (!serverState.IsOpen) - { return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason)); - } if (!ModelState.IsValid) - { return BadRequest(new ApiErrorResponse(ModelState)); - } - - var oFromDb = await ct.Tag.SingleOrDefaultAsync(m => m.Id == id); - - if (oFromDb == null) - { - return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); - } - - if (!Authorized.IsAuthorizedToModify(HttpContext.Items, AyaType.Tag, oFromDb.OwnerId)) - { - return StatusCode(401, new ApiNotAuthorizedResponse()); - } //Instantiate the business object handler - TagBiz biz = new TagBiz(ct, UserIdFromContext.Id(HttpContext.Items), UserRolesFromContext.Roles(HttpContext.Items)); + TagBiz biz = TagBiz.GetBiz(ct, HttpContext); - if (!biz.Put(oFromDb, oIn)) - { - return BadRequest(new ApiErrorResponse(biz.Errors)); - } + var oFromDb = await biz.GetAsync(id); + if (oFromDb == null) + return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); - //Log - EventLogProcessor.AddEntryToContextNoSave(new Event(biz.UserId, oFromDb.Id, AyaType.Tag, AyaEvent.Modified), ct); + if (!Authorized.IsAuthorizedToModify(HttpContext.Items, biz.BizType, oFromDb.OwnerId)) + return StatusCode(401, new ApiNotAuthorizedResponse()); try { - await ct.SaveChangesAsync(); + if (!biz.Put(oFromDb, oIn)) + return BadRequest(new ApiErrorResponse(biz.Errors)); } catch (DbUpdateConcurrencyException) { - if (!TagExists(id)) - { + if (!await biz.ExistsAsync(id)) return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); - } else - { - //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 Ok(new ApiOkResponse(new { ConcurrencyToken = oFromDb.ConcurrencyToken })); } @@ -261,59 +199,36 @@ namespace AyaNova.Api.Controllers [HttpPatch("{id}/{concurrencyToken}")] public async Task PatchTag([FromRoute] long id, [FromRoute] uint concurrencyToken, [FromBody]JsonPatchDocument objectPatch) { - //https://dotnetcoretutorials.com/2017/11/29/json-patch-asp-net-core/ if (!serverState.IsOpen) - { return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason)); - } if (!ModelState.IsValid) - { return BadRequest(new ApiErrorResponse(ModelState)); - } //Instantiate the business object handler - TagBiz biz = new TagBiz(ct, UserIdFromContext.Id(HttpContext.Items), UserRolesFromContext.Roles(HttpContext.Items)); - - - var oFromDb = await ct.Tag.SingleOrDefaultAsync(m => m.Id == id); + TagBiz biz = TagBiz.GetBiz(ct, HttpContext); + var oFromDb = await biz.GetAsync(id); if (oFromDb == null) - { return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); - } - if (!Authorized.IsAuthorizedToModify(HttpContext.Items, AyaType.Tag, oFromDb.OwnerId)) - { + if (!Authorized.IsAuthorizedToModify(HttpContext.Items, biz.BizType, oFromDb.OwnerId)) return StatusCode(401, new ApiNotAuthorizedResponse()); - } - - //patch and validate - if (!biz.Patch(oFromDb, objectPatch, concurrencyToken)) - { - return BadRequest(new ApiErrorResponse(biz.Errors)); - } - - //Log - EventLogProcessor.AddEntryToContextNoSave(new Event(biz.UserId, oFromDb.Id, AyaType.Tag, AyaEvent.Modified), ct); try { - await ct.SaveChangesAsync(); + //patch and validate + if (!biz.Patch(oFromDb, objectPatch, concurrencyToken)) + return BadRequest(new ApiErrorResponse(biz.Errors)); } catch (DbUpdateConcurrencyException) { - if (!TagExists(id)) - { + if (!await biz.ExistsAsync(id)) return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); - } else - { return StatusCode(409, new ApiErrorResponse(ApiErrorCode.CONCURRENCY_CONFLICT)); - } } - return Ok(new ApiOkResponse(new { ConcurrencyToken = oFromDb.ConcurrencyToken })); } @@ -327,42 +242,25 @@ namespace AyaNova.Api.Controllers [HttpPost("UntagAll/{id}")] public async Task UnTagEverything([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.Tag.SingleOrDefaultAsync(m => m.Id == id); - if (dbObj == null) - { - return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); - } - - if (!Authorized.IsAuthorizedToModify(HttpContext.Items, AyaType.Tag, dbObj.OwnerId)) - { - return StatusCode(401, new ApiNotAuthorizedResponse()); - } - - var UserId = UserIdFromContext.Id(HttpContext.Items); //Instantiate the business object handler - TagBiz biz = new TagBiz(ct, UserId, UserRolesFromContext.Roles(HttpContext.Items)); + TagBiz biz = TagBiz.GetBiz(ct, HttpContext); + + var dbObj = await biz.GetAsync(id); + if (dbObj == null) + return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); + + if (!Authorized.IsAuthorizedToModify(HttpContext.Items, biz.BizType, dbObj.OwnerId)) + return StatusCode(401, new ApiNotAuthorizedResponse()); //Untag from all places if (!biz.Untag(dbObj)) - { return BadRequest(new ApiErrorResponse(biz.Errors)); - } - - //Log - EventLogProcessor.AddEntryToContextNoSave(new Event(UserId, id, AyaType.Tag, AyaEvent.TagMassUntag), ct); - await ct.SaveChangesAsync(); return NoContent(); } @@ -377,55 +275,29 @@ namespace AyaNova.Api.Controllers [HttpDelete("{id}")] public async Task DeleteTag([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.Tag.SingleOrDefaultAsync(m => m.Id == id); - if (dbObj == null) - { - return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); - } - - if (!Authorized.IsAuthorizedToDelete(HttpContext.Items, AyaType.Tag, dbObj.OwnerId)) - { - return StatusCode(401, new ApiNotAuthorizedResponse()); - } //Instantiate the business object handler - TagBiz biz = new TagBiz(ct, UserIdFromContext.Id(HttpContext.Items), UserRolesFromContext.Roles(HttpContext.Items)); + TagBiz biz = TagBiz.GetBiz(ct, HttpContext); + + var dbObj = await biz.GetAsync(id); + if (dbObj == null) + return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); + + if (!Authorized.IsAuthorizedToDelete(HttpContext.Items, biz.BizType, dbObj.OwnerId)) + return StatusCode(401, new ApiNotAuthorizedResponse()); - //NOTE: ct.SaveChanges not required after this call - //Delete will look after it as it also needs to delete related records manull that are not mapped in EF Core if (!biz.Delete(dbObj)) - { return BadRequest(new ApiErrorResponse(biz.Errors)); - } - //Log - EventLogProcessor.DeleteObject(biz.UserId, AyaType.Tag, dbObj.Id, dbObj.Name, ct); - await ct.SaveChangesAsync(); - - return NoContent(); } - - private bool TagExists(long id) - { - return ct.Tag.Any(e => e.Id == id); - } - - - //------------ diff --git a/server/AyaNova/Controllers/WidgetController.cs b/server/AyaNova/Controllers/WidgetController.cs index 78cbc5bd..ab685159 100644 --- a/server/AyaNova/Controllers/WidgetController.cs +++ b/server/AyaNova/Controllers/WidgetController.cs @@ -326,7 +326,6 @@ namespace AyaNova.Api.Controllers } else { - //return success and link return CreatedAtAction("GetWidget", new { id = o.Id }, new ApiCreatedResponse(o)); } diff --git a/server/AyaNova/biz/BizObjectFactory.cs b/server/AyaNova/biz/BizObjectFactory.cs index 2191117e..68647ffc 100644 --- a/server/AyaNova/biz/BizObjectFactory.cs +++ b/server/AyaNova/biz/BizObjectFactory.cs @@ -28,7 +28,7 @@ namespace AyaNova.Biz case AyaType.Widget: return new WidgetBiz(dbcontext, userId, ServerBootConfig.AYANOVA_DEFAULT_LANGUAGE_ID, roles); case AyaType.Tag: - return new TagBiz(dbcontext, userId, roles); + return new TagBiz(dbcontext, userId, ServerBootConfig.AYANOVA_DEFAULT_LANGUAGE_ID, roles); case AyaType.TagMap: return new TagMapBiz(dbcontext, userId, roles); case AyaType.JobOperations: diff --git a/server/AyaNova/biz/TagBiz.cs b/server/AyaNova/biz/TagBiz.cs index b394c228..103fa380 100644 --- a/server/AyaNova/biz/TagBiz.cs +++ b/server/AyaNova/biz/TagBiz.cs @@ -20,17 +20,36 @@ namespace AyaNova.Biz public bool SeedOrImportRelaxedRulesMode { get; set; } - internal TagBiz(AyContext dbcontext, long currentUserId, AuthorizationRoles userRoles) + internal TagBiz(AyContext dbcontext, long currentUserId, long userLocaleId, AuthorizationRoles userRoles) { ct = dbcontext; UserId = currentUserId; + UserLocaleId = userLocaleId; CurrentUserRoles = userRoles; BizType = AyaType.Tag; SeedOrImportRelaxedRulesMode = false;//default } + internal static TagBiz GetBiz(AyContext ct, Microsoft.AspNetCore.Http.HttpContext httpContext) + { + return new TagBiz(ct, UserIdFromContext.Id(httpContext.Items), UserLocaleIdFromContext.Id(httpContext.Items), UserRolesFromContext.Roles(httpContext.Items)); + } + //////////////////////////////////////////////////////////////////////////////////////////////// + //EXISTS + internal async Task ExistsAsync(long id) + { + return await ct.Tag.AnyAsync(e => e.Id == id); + } + //////////////////////////////////////////////////////////////////////////////////////////////// + /// GET + internal async Task GetAsync(long fetchId) + { + //This is simple so nothing more here, but often will be copying to a different output object or some other ops + return await ct.Tag.SingleOrDefaultAsync(m => m.Id == fetchId); + } + //////////////////////////////////////////////////////////////////////////////////////////////// //CREATE @@ -51,6 +70,18 @@ namespace AyaNova.Biz await ct.Tag.AddAsync(outObj); + + await ct.SaveChangesAsync(); + + //Handle child and associated items: + + //EVENT LOG + EventLogProcessor.AddEntryToContextNoSave(new Event(UserId, outObj.Id, BizType, AyaEvent.Created), ct); + await ct.SaveChangesAsync(); + + //SEARCH INDEXING + Search.ProcessNewObjectKeywords(ct, UserLocaleId, outObj.Id, BizType, outObj.Name, outObj.Name); + return outObj; } } @@ -71,15 +102,7 @@ namespace AyaNova.Biz return inObj; } - //////////////////////////////////////////////////////////////////////////////////////////////// - /// GET - - //Get one - internal async Task GetAsync(long fetchId) - { - //This is simple so nothing more here, but often will be copying to a different output object or some other ops - return await ct.Tag.SingleOrDefaultAsync(m => m.Id == fetchId); - } + @@ -161,6 +184,13 @@ namespace AyaNova.Biz if (HasErrors) return false; + //Log modification + EventLogProcessor.AddEntryToContextNoSave(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct); + ct.SaveChanges(); + //Update keywords + Search.ProcessUpdatedObjectKeywords(ct, UserLocaleId, dbObj.Id, BizType, dbObj.Name, dbObj.Name); + + return true; } @@ -178,6 +208,14 @@ namespace AyaNova.Biz Validate(dbObj.Name, false); if (HasErrors) return false; + + //Log modification + EventLogProcessor.AddEntryToContextNoSave(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct); + ct.SaveChanges(); + //Update keywords + Search.ProcessUpdatedObjectKeywords(ct, UserLocaleId, dbObj.Id, BizType, dbObj.Name, dbObj.Name); + + return true; } @@ -194,6 +232,17 @@ namespace AyaNova.Biz if (HasErrors) return false; ct.Tag.Remove(dbObj); + ct.SaveChanges(); + + //Delete sibling objects + + //Event log process delete + EventLogProcessor.DeleteObject(UserId, BizType, dbObj.Id, dbObj.Name, ct); + ct.SaveChanges(); + + //Delete search index + Search.ProcessDeletedObjectKeywords(ct, dbObj.Id, BizType); + return true; } @@ -208,6 +257,9 @@ namespace AyaNova.Biz //npgsql driver will assume it's a string and put quotes around it triggering an error that a string can't be compared to an int ct.Database.ExecuteSqlCommand($"delete from atagmap where tagid = {dbObj.Id}"); ct.Database.ExecuteSqlCommand($"delete from ataggroupmap where tagid = {dbObj.Id}"); + //Log + EventLogProcessor.AddEntryToContextNoSave(new Event(UserId, dbObj.Id, BizType, AyaEvent.TagMassUntag), ct); + ct.SaveChanges(); return true; } diff --git a/server/AyaNova/biz/WidgetBiz.cs b/server/AyaNova/biz/WidgetBiz.cs index e326b139..757173f7 100644 --- a/server/AyaNova/biz/WidgetBiz.cs +++ b/server/AyaNova/biz/WidgetBiz.cs @@ -37,6 +37,8 @@ namespace AyaNova.Biz return new WidgetBiz(ct, 1, ServerBootConfig.AYANOVA_DEFAULT_LANGUAGE_ID, AuthorizationRoles.BizAdminFull); } + + //////////////////////////////////////////////////////////////////////////////////////////////// //CREATE internal async Task CreateAsync(Widget inObj)