public HttpResponseMessageWrapper <Item> DeleteItem(HttpRequestMessage req, Guid id) { Operation operation = null; HttpStatusCode code = AuthenticateUser(req); if (code != HttpStatusCode.OK) { // user not authenticated return(ReturnResult <Item>(req, operation, code)); } // get the item from the message body if one was passed Item clientItem; if (req.Content.Headers.ContentLength > 0) { clientItem = null; code = ProcessRequestBody(req, out clientItem, out operation); if (code != HttpStatusCode.OK) // error encountered processing body { return(ReturnResult <Item>(req, operation, code)); } if (clientItem.ID != id) { // IDs must match TraceLog.TraceError("ItemResource.Delete: Bad Request (ID in URL does not match entity body)"); return(ReturnResult <Item>(req, operation, HttpStatusCode.BadRequest)); } } else { // otherwise get the client item from the database try { clientItem = this.StorageContext.Items.Single <Item>(i => i.ID == id); var session = GetSessionFromMessageHeaders(req); operation = this.StorageContext.CreateOperation(CurrentUser, req.Method.Method, null, clientItem, null, session); } catch (Exception) { // item not found - it may have been deleted by someone else. Return 200 OK along with a dummy item. TraceLog.TraceInfo("ItemResource.Delete: entity not found; returned OK anyway"); return(ReturnResult <Item>(req, operation, new Item() { Name = "Item Not Found" }, HttpStatusCode.OK)); } } try { Folder folder = this.StorageContext.Folders.Single <Folder>(tl => tl.ID == clientItem.FolderID); if (folder.UserID != CurrentUser.ID) { // requested item does not belong to the authenticated user, return 403 Forbidden TraceLog.TraceError("ItemResource.Delete: Forbidden (entity's folder does not belong to current user)"); return(ReturnResult <Item>(req, operation, HttpStatusCode.Forbidden)); } try { Item requestedItem = this.StorageContext.Items.Include("ItemTags").Include("FieldValues").Single <Item>(t => t.ID == id); // process the delete BEFORE deleting item, fields, references, etc. ItemProcessor ip = ItemProcessor.Create(CurrentUser, StorageContext, requestedItem.ItemTypeID); if (ip != null) { // do itemtype-specific processing ip.ProcessDelete(requestedItem); } // delete all the itemtags associated with this item if (requestedItem.ItemTags != null && requestedItem.ItemTags.Count > 0) { foreach (var tt in requestedItem.ItemTags.ToList()) { this.StorageContext.ItemTags.Remove(tt); } } // delete all the fieldvalues associated with this item if (requestedItem.FieldValues != null && requestedItem.FieldValues.Count > 0) { foreach (var fv in requestedItem.FieldValues.ToList()) { this.StorageContext.FieldValues.Remove(fv); } } bool multipleItemsDeleted = false; // delete all the items with ParentID of this item.ID (recursively, from the bottom up) multipleItemsDeleted = DeleteItemChildrenRecursively(StorageContext, requestedItem); // delete all ItemRef FieldValues with Value of this item.ID multipleItemsDeleted |= DeleteItemReferences(CurrentUser, StorageContext, requestedItem); // TODO: indicate using TimeStamp that multiple items were deleted this.StorageContext.Items.Remove(requestedItem); if (this.StorageContext.SaveChanges() < 1) { TraceLog.TraceError("Internal Server Error (database operation did not succeed)"); return(ReturnResult <Item>(req, operation, HttpStatusCode.InternalServerError)); } else { if (folder.Name.StartsWith("$") == false) { WorkflowHost.WorkflowHost.InvokeWorkflowForOperation(this.StorageContext, null, operation); } TraceLog.TraceInfo("Accepted"); return(ReturnResult <Item>(req, operation, requestedItem, HttpStatusCode.Accepted)); } } catch (Exception ex) { // item not found - it may have been deleted by someone else. Return 200 OK along with a dummy item. TraceLog.TraceInfo(String.Format("Exception in database operation, return OK : Exception[{0}]", ex.Message)); return(ReturnResult <Item>(req, operation, new Item() { Name = "Item Not Found" }, HttpStatusCode.OK)); } } catch (Exception ex) { // folder not found - return 404 Not Found TraceLog.TraceException(String.Format("Resource not found (Folder)"), ex); return(ReturnResult <Item>(req, operation, HttpStatusCode.NotFound)); } }
public HttpResponseMessageWrapper <Item> UpdateItem(HttpRequestMessage req, Guid id) { Operation operation = null; HttpStatusCode code = AuthenticateUser(req); if (code != HttpStatusCode.OK) { // user not authenticated return(ReturnResult <Item>(req, operation, code)); } List <Item> clientItems = null; code = ProcessRequestBody <List <Item> >(req, out clientItems, out operation); if (code != HttpStatusCode.OK) // error encountered processing body { return(ReturnResult <Item>(req, operation, code)); } Item originalItem = clientItems[0]; Item newItem = clientItems[1]; // make sure the item ID's match if (originalItem.ID != id || newItem.ID != id) { TraceLog.TraceError("ID in URL does not match entity body"); return(ReturnResult <Item>(req, operation, HttpStatusCode.BadRequest)); } // if parent ID is an empty guid, make it null instead so as to not violate ref integrity rules if (originalItem.ParentID == Guid.Empty) { originalItem.ParentID = null; } if (newItem.ParentID == Guid.Empty) { newItem.ParentID = null; } if (newItem.LastModified.Year == 1970) { // web client sets Date(0) to get server timestamp (ticks since 1970) newItem.LastModified = DateTime.UtcNow; } // get the folder for the item try { Item requestedItem = this.StorageContext.Items.Include("ItemTags").Include("FieldValues").Single <Item>(t => t.ID == id); // if the Folder does not belong to the authenticated user, return 403 Forbidden if (requestedItem.UserID != CurrentUser.ID) { TraceLog.TraceError("Entity does not belong to current user)"); return(ReturnResult <Item>(req, operation, HttpStatusCode.Forbidden)); } // reset the UserID fields to the appropriate user, to ensure update is done in the context of the current user originalItem.UserID = requestedItem.UserID; newItem.UserID = requestedItem.UserID; Folder originalFolder = this.StorageContext.Folders.Single <Folder>(tl => tl.ID == originalItem.FolderID); Folder newFolder = this.StorageContext.Folders.Single <Folder>(tl => tl.ID == newItem.FolderID); if (originalFolder.UserID != CurrentUser.ID || newFolder.UserID != CurrentUser.ID || originalItem.UserID != CurrentUser.ID || newItem.UserID != CurrentUser.ID) { // folder or item does not belong to the authenticated user, return 403 Forbidden TraceLog.TraceError("Folder of Entity does not belong to current user)"); return(ReturnResult <Item>(req, operation, HttpStatusCode.Forbidden)); } try { bool changed = false; if (requestedItem.ItemTags != null && requestedItem.ItemTags.Count > 0) { // delete all the itemtags associated with this item foreach (var tt in requestedItem.ItemTags.ToList()) { this.StorageContext.ItemTags.Remove(tt); } changed = true; } ItemProcessor ip = ItemProcessor.Create(CurrentUser, StorageContext, newItem.ItemTypeID); if (ip != null) { // do itemtype-specific processing ip.ProcessUpdate(originalItem, newItem); } // call update and make sure the changed flag reflects the outcome correctly changed = (Update(requestedItem, originalItem, newItem) == true ? true : changed); if (changed == true) { int rows = this.StorageContext.SaveChanges(); if (rows < 0) { TraceLog.TraceError("Internal Server Error (database operation did not succeed)"); return(ReturnResult <Item>(req, operation, HttpStatusCode.InternalServerError)); } else { if (rows == 0) { TraceLog.TraceInfo("Inconsistency between the results of Update and zero rows affected"); } if (newFolder.Name.StartsWith("$") == false) { WorkflowHost.WorkflowHost.InvokeWorkflowForOperation(this.StorageContext, null, operation); } TraceLog.TraceInfo("Accepted"); return(ReturnResult <Item>(req, operation, requestedItem, HttpStatusCode.Accepted)); } } else { TraceLog.TraceInfo("Accepted (no changes)"); return(ReturnResult <Item>(req, operation, requestedItem, HttpStatusCode.Accepted)); } } catch (Exception ex) { // item not found - return 404 Not Found TraceLog.TraceException("Resource not found (Item)", ex); return(ReturnResult <Item>(req, operation, HttpStatusCode.NotFound)); } } catch (Exception ex) { // folder not found - return 404 Not Found TraceLog.TraceException("Resource not found (Folder)", ex); return(ReturnResult <Item>(req, operation, HttpStatusCode.NotFound)); } }
public HttpResponseMessageWrapper <Item> InsertItem(HttpRequestMessage req) { Operation operation = null; HttpStatusCode code = AuthenticateUser(req); if (code != HttpStatusCode.OK) { // user not authenticated return(ReturnResult <Item>(req, operation, code)); } // get the new item from the message body Item clientItem = null; code = ProcessRequestBody <Item>(req, out clientItem, out operation); if (code != HttpStatusCode.OK) // error encountered processing body { return(ReturnResult <Item>(req, operation, code)); } if (clientItem.ParentID == Guid.Empty) { // parent ID is an empty guid, make it null instead so as to not violate ref integrity rules clientItem.ParentID = null; } try { Folder folder = this.StorageContext.Folders.Single <Folder>(tl => tl.ID == clientItem.FolderID); if (folder.UserID != CurrentUser.ID) { // requested folder does not belong to the authenticated user, return 403 Forbidden TraceLog.TraceError("Folder of Entity does not belong to current user)"); return(ReturnResult <Item>(req, operation, HttpStatusCode.Forbidden)); } // fill out the ID's for any FieldValues that travelled with the item if (clientItem.FieldValues != null) { foreach (var fv in clientItem.FieldValues) { if (fv.ItemID == null || fv.ItemID == Guid.Empty) { fv.ItemID = clientItem.ID; } } } // fill out the timestamps if they aren't set (null, or MinValue.Date, allowing for DST and timezone issues) DateTime now = DateTime.UtcNow; if (clientItem.Created == null || clientItem.Created.Date == DateTime.MinValue.Date) { clientItem.Created = now; } if (clientItem.LastModified == null || clientItem.LastModified.Date == DateTime.MinValue.Date) { clientItem.LastModified = now; } ItemProcessor ip = ItemProcessor.Create(CurrentUser, StorageContext, clientItem.ItemTypeID); if (ip != null) { // do itemtype-specific processing ip.ProcessCreate(clientItem); } try { // add the new item to the database var item = this.StorageContext.Items.Add(clientItem); int rows = this.StorageContext.SaveChanges(); if (rows < 1 || item == null) { TraceLog.TraceError("Internal Server Error (database operation did not succeed)"); return(ReturnResult <Item>(req, operation, HttpStatusCode.InternalServerError)); // return 500 Internal Server Error } else { // invoke any workflows associated with this item if (folder.Name.StartsWith("$") == false) { WorkflowHost.WorkflowHost.InvokeWorkflowForOperation(this.StorageContext, null, operation); } TraceLog.TraceInfo("Created"); return(ReturnResult <Item>(req, operation, item, HttpStatusCode.Created)); // return 201 Created } } catch (Exception ex) { // check for the condition where the item is already in the database // in that case, return 202 Accepted; otherwise, return 500 Internal Server Error try { var dbItem = this.StorageContext.Items.Single(t => t.ID == clientItem.ID); if (dbItem.Name == clientItem.Name) { TraceLog.TraceInfo("Accepted (entity already in database) : Exception[" + ex.Message + "]"); return(ReturnResult <Item>(req, operation, dbItem, HttpStatusCode.Accepted)); } else { TraceLog.TraceException("Error inserting entity", ex); return(ReturnResult <Item>(req, operation, HttpStatusCode.InternalServerError)); } } catch (Exception) { // item not inserted - return 500 Internal Server Error TraceLog.TraceException("Error inserting entity", ex); return(ReturnResult <Item>(req, operation, HttpStatusCode.InternalServerError)); } } } catch (Exception ex) { // folder not found - return 404 Not Found TraceLog.TraceException("Resource not found (Folder)", ex); return(ReturnResult <Item>(req, operation, HttpStatusCode.NotFound)); } }