public ContentItemDisplay PostSave( [ModelBinder(typeof(ContentItemBinder))] ContentItemSave contentItem) { return(PostSaveInternal(contentItem, content => Services.ContentService.WithResult().Save(contentItem.PersistedContent, Security.CurrentUser.Id))); }
/// <summary> /// Maps the dto property values to the persisted model /// </summary> /// <param name="contentItem"></param> private void MapPropertyValues(ContentItemSave contentItem) { UpdateName(contentItem); //TODO: We need to support 'send to publish' contentItem.PersistedContent.ExpireDate = contentItem.ExpireDate; contentItem.PersistedContent.ReleaseDate = contentItem.ReleaseDate; //only set the template if it didn't change var templateChanged = (contentItem.PersistedContent.Template == null && contentItem.TemplateAlias.IsNullOrWhiteSpace() == false) || (contentItem.PersistedContent.Template != null && contentItem.PersistedContent.Template.Alias != contentItem.TemplateAlias) || (contentItem.PersistedContent.Template != null && contentItem.TemplateAlias.IsNullOrWhiteSpace()); if (templateChanged) { var template = Services.FileService.GetTemplate(contentItem.TemplateAlias); if (template == null && contentItem.TemplateAlias.IsNullOrWhiteSpace() == false) { //ModelState.AddModelError("Template", "No template exists with the specified alias: " + contentItem.TemplateAlias); LogHelper.Warn <ContentController>("No template exists with the specified alias: " + contentItem.TemplateAlias); } else { //NOTE: this could be null if there was a template and the posted template is null, this should remove the assigned template contentItem.PersistedContent.Template = template; } } base.MapPropertyValues(contentItem); }
internal static void BindModel(ContentItemSave model, IContent persistedContent, ContentModelBinderHelper modelBinderHelper, IUmbracoMapper umbracoMapper) { model.PersistedContent = persistedContent; //create the dto from the persisted model if (model.PersistedContent != null) { foreach (ContentVariantSave variant in model.Variants) { //map the property dto collection with the culture of the current variant variant.PropertyCollectionDto = umbracoMapper.Map <ContentPropertyCollectionDto>( model.PersistedContent, context => { // either of these may be null and that is ok, if it's invariant they will be null which is what is expected context.SetCulture(variant.Culture); context.SetSegment(variant.Segment); }); //now map all of the saved values to the dto modelBinderHelper.MapPropertyValuesFromSaved(variant, variant.PropertyCollectionDto); } } }
/// <summary> /// If there are no variants tagged for Saving, then this is an invalid request /// </summary> /// <param name="contentItem"></param> /// <param name="actionContext"></param> /// <returns></returns> private bool ValidateAtLeastOneVariantIsBeingSaved(ContentItemSave contentItem, HttpActionContext actionContext) { if (!contentItem.Variants.Any(x => x.Save)) { actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, "No variants flagged for saving"); return(false); } return(true); }
//TODO: Validate the property type data private bool ValidateData(ContentItemSave postedItem, ContentItemDto realItem, HttpActionContext actionContext) { foreach (var p in realItem.Properties) { var editor = PropertyEditorResolver.Current.GetById(p.DataType.ControlId); if (editor == null) { var message = string.Format("The property editor with id: {0} was not found for property with id {1}", p.DataType.ControlId, p.Id); actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, message); return(false); } //get the posted value for this property var postedValue = postedItem.Properties.Single(x => x.Id == p.Id).Value; //get the pre-values for this property var preValues = TestContentService.GetPreValue(p.DataType.Id); //TODO: when we figure out how to 'override' certain pre-value properties we'll either need to: // * Combine the preValues with the overridden values stored with the document type property (but how to combine?) // * Or, pass in the overridden values stored with the doc type property separately foreach (var v in editor.ValueEditor.Validators) { foreach (var result in v.Validate(postedValue, preValues, editor)) { //if there are no member names supplied then we assume that the validation message is for the overall property // not a sub field on the property editor if (!result.MemberNames.Any()) { //add a model state error for the entire property actionContext.ModelState.AddModelError(p.Alias, result.ErrorMessage); } else { //there's assigned field names so we'll combine the field name with the property name // so that we can try to match it up to a real sub field of this editor foreach (var field in result.MemberNames) { actionContext.ModelState.AddModelError(string.Format("{0}.{1}", p.Alias, field), result.ErrorMessage); } } } } } //create the response if there any errors if (!actionContext.ModelState.IsValid) { actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Forbidden, actionContext.ModelState); } return(actionContext.ModelState.IsValid); }
//TODO: Validate the property type data private bool ValidateData(ContentItemSave postedItem, ContentItemDto realItem, HttpActionContext actionContext) { foreach (var p in realItem.Properties) { var editor = PropertyEditorResolver.Current.GetById(p.DataType.ControlId); if (editor == null) { var message = string.Format("The property editor with id: {0} was not found for property with id {1}", p.DataType.ControlId, p.Id); actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, message); return false; } //get the posted value for this property var postedValue = postedItem.Properties.Single(x => x.Id == p.Id).Value; //get the pre-values for this property var preValues = TestContentService.GetPreValue(p.DataType.Id); //TODO: when we figure out how to 'override' certain pre-value properties we'll either need to: // * Combine the preValues with the overridden values stored with the document type property (but how to combine?) // * Or, pass in the overridden values stored with the doc type property separately foreach (var v in editor.ValueEditor.Validators) { foreach (var result in v.Validate(postedValue, preValues, editor)) { //if there are no member names supplied then we assume that the validation message is for the overall property // not a sub field on the property editor if (!result.MemberNames.Any()) { //add a model state error for the entire property actionContext.ModelState.AddModelError(p.Alias, result.ErrorMessage); } else { //there's assigned field names so we'll combine the field name with the property name // so that we can try to match it up to a real sub field of this editor foreach (var field in result.MemberNames) { actionContext.ModelState.AddModelError(string.Format("{0}.{1}", p.Alias, field), result.ErrorMessage); } } } } } //create the response if there any errors if (!actionContext.ModelState.IsValid) { actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Forbidden, actionContext.ModelState); } return actionContext.ModelState.IsValid; }
public HttpResponseMessage PostSaveContent( [ModelBinder(typeof(ContentItemBinder))] ContentItemSave contentItem) { //If we've reached here it means: // * Our model has been bound // * and validated // * any file attachments have been saved to their temporary location for us to use return(Request.CreateResponse(HttpStatusCode.OK, "success!")); }
/// <summary> /// Ensure the content exists /// </summary> /// <param name="postedItem"></param> /// <param name="actionContext"></param> /// <param name="found"></param> /// <returns></returns> private bool ValidateExistingContent(ContentItemSave postedItem, HttpActionContext actionContext, out ContentItemDto found) { //TODO: We need to of course change this to the real umbraco api found = TestContentService.GetContentItem(postedItem.Id); if (found == null) { var message = string.Format("content with id: {0} was not found", postedItem.Id); actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, message); return(false); } return(true); }
/// <summary> /// If there are no variants tagged for Saving, then this is an invalid request /// </summary> /// <param name="contentItem"></param> /// <param name="actionContext"></param> /// <returns></returns> private bool ValidateAtLeastOneVariantIsBeingSaved( ContentItemSave contentItem, ActionExecutingContext actionContext) { if (!contentItem.Variants.Any(x => x.Save)) { actionContext.Result = new NotFoundObjectResult(new { Message = "No variants flagged for saving" }); return(false); } return(true); }
private IContent CreateNew(ContentItemSave model) { var contentType = Services.ContentTypeService.Get(model.ContentTypeAlias); if (contentType == null) { throw new InvalidOperationException("No content type found with alias " + model.ContentTypeAlias); } return(new Content( contentType.VariesByCulture() ? null : model.Variants.First().Name, model.ParentId, contentType)); }
/// <summary> /// Ensure all of the ids in the post are valid /// </summary> /// <param name="postedItem"></param> /// <param name="actionContext"></param> /// <param name="realItem"></param> /// <returns></returns> private bool ValidateProperties(ContentItemSave postedItem, ContentItemDto realItem, HttpActionContext actionContext) { foreach (var p in postedItem.Properties) { //ensure the property actually exists in our server side properties if (!realItem.Properties.Contains(p)) { //TODO: Do we return errors here ? If someone deletes a property whilst their editing then should we just //save the property data that remains? Or inform them they need to reload... not sure. This problem exists currently too i think. var message = string.Format("property with id: {0} was not found", p.Id); actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, message); return(false); } } return(true); }
public ContentItemDisplay PostSaveBlueprint( [ModelBinder(typeof(ContentItemBinder))] ContentItemSave contentItem) { var contentItemDisplay = PostSaveInternal(contentItem, content => { EnsureUniqueName(content.Name, content, "Name"); Services.ContentService.SaveBlueprint(contentItem.PersistedContent, Security.CurrentUser.Id); //we need to reuse the underlying logic so return the result that it wants return(Attempt <OperationStatus> .Succeed(new OperationStatus(OperationStatusType.Success, new EventMessages()))); }); SetupBlueprint(contentItemDisplay, contentItemDisplay.PersistedContent); return(contentItemDisplay); }
/// <summary> /// Maps the dto property values to the persisted model /// </summary> /// <param name="contentItem"></param> private void MapPropertyValues(ContentItemSave contentItem) { UpdateName(contentItem); //TODO: We need to support 'send to publish' contentItem.PersistedContent.ExpireDate = contentItem.ExpireDate; contentItem.PersistedContent.ReleaseDate = contentItem.ReleaseDate; //only set the template if it didn't change var templateChanged = (contentItem.PersistedContent.Template == null && contentItem.TemplateAlias.IsNullOrWhiteSpace() == false) || (contentItem.PersistedContent.Template != null && contentItem.PersistedContent.Template.Alias != contentItem.TemplateAlias) || (contentItem.PersistedContent.Template != null && contentItem.TemplateAlias.IsNullOrWhiteSpace()); if (templateChanged) { var template = Services.FileService.GetTemplate(contentItem.TemplateAlias); if (template == null && contentItem.TemplateAlias.IsNullOrWhiteSpace() == false) { //ModelState.AddModelError("Template", "No template exists with the specified alias: " + contentItem.TemplateAlias); LogHelper.Warn<ContentController>("No template exists with the specified alias: " + contentItem.TemplateAlias); } else { //NOTE: this could be null if there was a template and the posted template is null, this should remove the assigned template contentItem.PersistedContent.Template = template; } } base.MapPropertyValues(contentItem); }
protected override IContent GetExisting(ContentItemSave model) { return(ApplicationContext.Services.ContentService.GetBlueprintById(Convert.ToInt32(model.Id))); }
public void Validating_ContentItemSave() { var validator = new ContentSaveModelValidator( Factory.GetInstance <ILogger>(), Mock.Of <IUmbracoContextAccessor>(), Factory.GetInstance <ILocalizedTextService>()); var content = MockedContent.CreateTextpageContent(_contentType, "test", -1); var id1 = new Guid("c8df5136-d606-41f0-9134-dea6ae0c2fd9"); var id2 = new Guid("f916104a-4082-48b2-a515-5c4bf2230f38"); var id3 = new Guid("77E15DE9-1C79-47B2-BC60-4913BC4D4C6A"); // TODO: Ok now test with a 4th level complex nested editor var complexValue = @"[{ ""key"": """ + id1.ToString() + @""", ""name"": ""Hello world"", ""ncContentTypeAlias"": """ + ContentTypeAlias + @""", ""title"": ""Hello world"", ""bodyText"": ""The world is round"" }, { ""key"": """ + id2.ToString() + @""", ""name"": ""Super nested"", ""ncContentTypeAlias"": """ + ContentTypeAlias + @""", ""title"": ""Hi there!"", ""bodyText"": ""Well hello there"", ""complex"" : [{ ""key"": """ + id3.ToString() + @""", ""name"": ""I am a sub nested content"", ""ncContentTypeAlias"": """ + ContentTypeAlias + @""", ""title"": ""Hello up there :)"", ""bodyText"": ""Hello way up there on a different level"" }] } ]"; content.SetValue("complex", complexValue); // map the persisted properties to a model representing properties to save //var saveProperties = content.Properties.Select(x => Mapper.Map<ContentPropertyBasic>(x)).ToList(); var saveProperties = content.Properties.Select(x => { return(new ContentPropertyBasic { Alias = x.Alias, Id = x.Id, Value = x.GetValue() }); }).ToList(); var saveVariants = new List <ContentVariantSave> { new ContentVariantSave { Culture = string.Empty, Segment = string.Empty, Name = content.Name, Save = true, Properties = saveProperties } }; var save = new ContentItemSave { Id = content.Id, Action = ContentSaveAction.Save, ContentTypeAlias = _contentType.Alias, ParentId = -1, PersistedContent = content, TemplateAlias = null, Variants = saveVariants }; // This will map the ContentItemSave.Variants.PropertyCollectionDto and then map the values in the saved model // back onto the persisted IContent model. ContentItemBinder.BindModel(save, content); var modelState = new ModelStateDictionary(); var isValid = validator.ValidatePropertiesData(save, saveVariants[0], saveVariants[0].PropertyCollectionDto, modelState); // list results for debugging foreach (var state in modelState) { Console.WriteLine(state.Key); foreach (var error in state.Value.Errors) { Console.WriteLine("\t" + error.ErrorMessage); } } // assert Assert.IsFalse(isValid); Assert.AreEqual(11, modelState.Keys.Count); const string complexPropertyKey = "_Properties.complex.invariant.null"; Assert.IsTrue(modelState.Keys.Contains(complexPropertyKey)); foreach (var state in modelState.Where(x => x.Key != complexPropertyKey)) { foreach (var error in state.Value.Errors) { Assert.IsFalse(error.ErrorMessage.DetectIsJson()); // non complex is just an error message } } var complexEditorErrors = modelState.Single(x => x.Key == complexPropertyKey).Value.Errors; Assert.AreEqual(1, complexEditorErrors.Count); var nestedError = complexEditorErrors[0]; var jsonError = JsonConvert.DeserializeObject <JArray>(nestedError.ErrorMessage); var modelStateKeys = new[] { "_Properties.title.invariant.null.innerFieldId", "_Properties.title.invariant.null.value", "_Properties.bodyText.invariant.null.innerFieldId", "_Properties.bodyText.invariant.null.value" }; AssertNestedValidation(jsonError, 0, id1, modelStateKeys); AssertNestedValidation(jsonError, 1, id2, modelStateKeys.Concat(new[] { "_Properties.complex.invariant.null.innerFieldId", "_Properties.complex.invariant.null.value" }).ToArray()); var nestedJsonError = jsonError.SelectToken("$[1].complex") as JArray; Assert.IsNotNull(nestedJsonError); AssertNestedValidation(nestedJsonError, 0, id3, modelStateKeys); }
protected virtual IContent?GetExisting(ContentItemSave model) => _contentService.GetById(model.Id);
public static IContent GetPersistedContent(ContentItemSave item) => PersistedContentGetter(item);
protected override IContent GetExisting(ContentItemSave model) { return(Services.ContentService.GetBlueprintById(model.Id)); }
public static string GetUpdateDateOverrideString([NotNull] this ContentItemSave item) { Argument.NotNull(nameof(item), item); return((string)GetValueOrDefault(item.AdditionalData, UpdateDateOverrideKey)); }
public ContentItemDisplay PostSave( [ModelBinder(typeof(ContentItemBinder))] ContentItemSave contentItem) { //If we've reached here it means: // * Our model has been bound // * and validated // * any file attachments have been saved to their temporary location for us to use // * we have a reference to the DTO object and the persisted object // * Permissions are valid MapPropertyValues(contentItem); //We need to manually check the validation results here because: // * We still need to save the entity even if there are validation value errors // * Depending on if the entity is new, and if there are non property validation errors (i.e. the name is null) // then we cannot continue saving, we can only display errors // * If there are validation errors and they were attempting to publish, we can only save, NOT publish and display // a message indicating this if (ModelState.IsValid == false) { if (ValidationHelper.ModelHasRequiredForPersistenceErrors(contentItem) && IsCreatingAction(contentItem.Action)) { //ok, so the absolute mandatory data is invalid and it's new, we cannot actually continue! // add the modelstate to the outgoing object and throw a validation message var forDisplay = Mapper.Map <IContent, ContentItemDisplay>(contentItem.PersistedContent); forDisplay.Errors = ModelState.ToErrorDictionary(); throw new HttpResponseException(Request.CreateValidationErrorResponse(forDisplay)); } //if the model state is not valid we cannot publish so change it to save switch (contentItem.Action) { case ContentSaveAction.Publish: contentItem.Action = ContentSaveAction.Save; break; case ContentSaveAction.PublishNew: contentItem.Action = ContentSaveAction.SaveNew; break; } } //initialize this to successful var publishStatus = Attempt <PublishStatus> .Succeed(); var wasCancelled = false; if (contentItem.Action == ContentSaveAction.Save || contentItem.Action == ContentSaveAction.SaveNew) { //save the item var saveResult = Services.ContentService.WithResult().Save(contentItem.PersistedContent, Security.CurrentUser.Id); wasCancelled = saveResult.Success == false && saveResult.Result.StatusType == OperationStatusType.FailedCancelledByEvent; } else if (contentItem.Action == ContentSaveAction.SendPublish || contentItem.Action == ContentSaveAction.SendPublishNew) { var sendResult = Services.ContentService.SendToPublication(contentItem.PersistedContent, Security.CurrentUser.Id); wasCancelled = sendResult == false; } else { //publish the item and check if it worked, if not we will show a diff msg below publishStatus = Services.ContentService.SaveAndPublishWithStatus(contentItem.PersistedContent, Security.CurrentUser.Id); wasCancelled = publishStatus.Result.StatusType == PublishStatusType.FailedCancelledByEvent; } //return the updated model var display = Mapper.Map <IContent, ContentItemDisplay>(contentItem.PersistedContent); //lasty, if it is not valid, add the modelstate to the outgoing object and throw a 403 HandleInvalidModelState(display); //put the correct msgs in switch (contentItem.Action) { case ContentSaveAction.Save: case ContentSaveAction.SaveNew: if (wasCancelled == false) { display.AddSuccessNotification( Services.TextService.Localize("speechBubbles/editContentSavedHeader"), Services.TextService.Localize("speechBubbles/editContentSavedText")); } else { AddCancelMessage(display); } break; case ContentSaveAction.SendPublish: case ContentSaveAction.SendPublishNew: if (wasCancelled == false) { display.AddSuccessNotification( Services.TextService.Localize("speechBubbles/editContentSendToPublish"), Services.TextService.Localize("speechBubbles/editContentSendToPublishText")); } else { AddCancelMessage(display); } break; case ContentSaveAction.Publish: case ContentSaveAction.PublishNew: ShowMessageForPublishStatus(publishStatus.Result, display); break; } UpdatePreviewContext(contentItem.PersistedContent.Id); //If the item is new and the operation was cancelled, we need to return a different // status code so the UI can handle it since it won't be able to redirect since there // is no Id to redirect to! if (wasCancelled && IsCreatingAction(contentItem.Action)) { throw new HttpResponseException(Request.CreateValidationErrorResponse(display)); } return(display); }
/// <summary> /// Checks if the user has access to post a content item based on whether it's being created or saved. /// </summary> /// <param name="actionContext"></param> /// <param name="contentItem"></param> /// <param name="backofficeSecurity"></param> private async Task <bool> ValidateUserAccessAsync( ContentItemSave contentItem, ActionExecutingContext actionContext) { // We now need to validate that the user is allowed to be doing what they are doing. // Based on the action we need to check different permissions. // Then if it is new, we need to lookup those permissions on the parent! var permissionToCheck = new List <char>(); IContent contentToCheck = null; int contentIdToCheck; switch (contentItem.Action) { case ContentSaveAction.Save: permissionToCheck.Add(ActionUpdate.ActionLetter); contentToCheck = contentItem.PersistedContent; contentIdToCheck = contentToCheck.Id; break; case ContentSaveAction.Publish: case ContentSaveAction.PublishWithDescendants: case ContentSaveAction.PublishWithDescendantsForce: permissionToCheck.Add(ActionPublish.ActionLetter); contentToCheck = contentItem.PersistedContent; contentIdToCheck = contentToCheck.Id; break; case ContentSaveAction.SendPublish: permissionToCheck.Add(ActionToPublish.ActionLetter); contentToCheck = contentItem.PersistedContent; contentIdToCheck = contentToCheck.Id; break; case ContentSaveAction.Schedule: permissionToCheck.Add(ActionUpdate.ActionLetter); permissionToCheck.Add(ActionToPublish.ActionLetter); contentToCheck = contentItem.PersistedContent; contentIdToCheck = contentToCheck.Id; break; case ContentSaveAction.SaveNew: //Save new requires ActionNew permissionToCheck.Add(ActionNew.ActionLetter); if (contentItem.ParentId != Constants.System.Root) { contentToCheck = _contentService.GetById(contentItem.ParentId); contentIdToCheck = contentToCheck.Id; } else { contentIdToCheck = contentItem.ParentId; } break; case ContentSaveAction.SendPublishNew: //Send new requires both ActionToPublish AND ActionNew permissionToCheck.Add(ActionNew.ActionLetter); permissionToCheck.Add(ActionToPublish.ActionLetter); if (contentItem.ParentId != Constants.System.Root) { contentToCheck = _contentService.GetById(contentItem.ParentId); contentIdToCheck = contentToCheck.Id; } else { contentIdToCheck = contentItem.ParentId; } break; case ContentSaveAction.PublishNew: case ContentSaveAction.PublishWithDescendantsNew: case ContentSaveAction.PublishWithDescendantsForceNew: //Publish new requires both ActionNew AND ActionPublish // TODO: Shouldn't publish also require ActionUpdate since it will definitely perform an update to publish but maybe that's just implied permissionToCheck.Add(ActionNew.ActionLetter); permissionToCheck.Add(ActionPublish.ActionLetter); if (contentItem.ParentId != Constants.System.Root) { contentToCheck = _contentService.GetById(contentItem.ParentId); contentIdToCheck = contentToCheck.Id; } else { contentIdToCheck = contentItem.ParentId; } break; case ContentSaveAction.ScheduleNew: permissionToCheck.Add(ActionNew.ActionLetter); permissionToCheck.Add(ActionUpdate.ActionLetter); permissionToCheck.Add(ActionPublish.ActionLetter); if (contentItem.ParentId != Constants.System.Root) { contentToCheck = _contentService.GetById(contentItem.ParentId); contentIdToCheck = contentToCheck.Id; } else { contentIdToCheck = contentItem.ParentId; } break; default: throw new ArgumentOutOfRangeException(); } var resource = contentToCheck == null ? new ContentPermissionsResource(contentToCheck, contentIdToCheck, permissionToCheck) : new ContentPermissionsResource(contentToCheck, permissionToCheck); var authorizationResult = await _authorizationService.AuthorizeAsync( actionContext.HttpContext.User, resource, AuthorizationPolicies.ContentPermissionByResource); if (!authorizationResult.Succeeded) { return(false); } return(true); }
protected virtual IContent GetExisting(ContentItemSave model) { return(Services.ContentService.GetById(model.Id)); }
/// <summary> /// Checks if the user has access to post a content item based on whether it's being created or saved. /// </summary> /// <param name="actionContext"></param> /// <param name="contentItem"></param> private bool ValidateUserAccess(ContentItemSave contentItem, HttpActionContext actionContext) { //We now need to validate that the user is allowed to be doing what they are doing. //Based on the action we need to check different permissions. //Then if it is new, we need to lookup those permissions on the parent! var permissionToCheck = new List <char>(); IContent contentToCheck = null; int contentIdToCheck; switch (contentItem.Action) { case ContentSaveAction.Save: permissionToCheck.Add(ActionUpdate.ActionLetter); contentToCheck = contentItem.PersistedContent; contentIdToCheck = contentToCheck.Id; break; case ContentSaveAction.Publish: case ContentSaveAction.PublishWithDescendants: case ContentSaveAction.PublishWithDescendantsForce: permissionToCheck.Add(ActionPublish.ActionLetter); contentToCheck = contentItem.PersistedContent; contentIdToCheck = contentToCheck.Id; break; case ContentSaveAction.SendPublish: permissionToCheck.Add(ActionToPublish.ActionLetter); contentToCheck = contentItem.PersistedContent; contentIdToCheck = contentToCheck.Id; break; case ContentSaveAction.Schedule: permissionToCheck.Add(ActionUpdate.ActionLetter); permissionToCheck.Add(ActionToPublish.ActionLetter); contentToCheck = contentItem.PersistedContent; contentIdToCheck = contentToCheck.Id; break; case ContentSaveAction.SaveNew: //Save new requires ActionNew permissionToCheck.Add(ActionNew.ActionLetter); if (contentItem.ParentId != Constants.System.Root) { contentToCheck = _contentService.GetById(contentItem.ParentId); contentIdToCheck = contentToCheck.Id; } else { contentIdToCheck = contentItem.ParentId; } break; case ContentSaveAction.SendPublishNew: //Send new requires both ActionToPublish AND ActionNew permissionToCheck.Add(ActionNew.ActionLetter); permissionToCheck.Add(ActionToPublish.ActionLetter); if (contentItem.ParentId != Constants.System.Root) { contentToCheck = _contentService.GetById(contentItem.ParentId); contentIdToCheck = contentToCheck.Id; } else { contentIdToCheck = contentItem.ParentId; } break; case ContentSaveAction.PublishNew: case ContentSaveAction.PublishWithDescendantsNew: case ContentSaveAction.PublishWithDescendantsForceNew: //Publish new requires both ActionNew AND ActionPublish //TODO: Shoudn't publish also require ActionUpdate since it will definitely perform an update to publish but maybe that's just implied permissionToCheck.Add(ActionNew.ActionLetter); permissionToCheck.Add(ActionPublish.ActionLetter); if (contentItem.ParentId != Constants.System.Root) { contentToCheck = _contentService.GetById(contentItem.ParentId); contentIdToCheck = contentToCheck.Id; } else { contentIdToCheck = contentItem.ParentId; } break; case ContentSaveAction.ScheduleNew: permissionToCheck.Add(ActionNew.ActionLetter); permissionToCheck.Add(ActionUpdate.ActionLetter); permissionToCheck.Add(ActionPublish.ActionLetter); if (contentItem.ParentId != Constants.System.Root) { contentToCheck = _contentService.GetById(contentItem.ParentId); contentIdToCheck = contentToCheck.Id; } else { contentIdToCheck = contentItem.ParentId; } break; default: throw new ArgumentOutOfRangeException(); } ContentPermissionsHelper.ContentAccess accessResult; if (contentToCheck != null) { //store the content item in request cache so it can be resolved in the controller without re-looking it up actionContext.Request.Properties[typeof(IContent).ToString()] = contentItem; accessResult = ContentPermissionsHelper.CheckPermissions( contentToCheck, _security.CurrentUser, _userService, _entityService, permissionToCheck.ToArray()); } else { accessResult = ContentPermissionsHelper.CheckPermissions( contentIdToCheck, _security.CurrentUser, _userService, _contentService, _entityService, out contentToCheck, permissionToCheck.ToArray()); if (contentToCheck != null) { //store the content item in request cache so it can be resolved in the controller without re-looking it up actionContext.Request.Properties[typeof(IContent).ToString()] = contentToCheck; } } if (accessResult == ContentPermissionsHelper.ContentAccess.NotFound) { throw new HttpResponseException(HttpStatusCode.NotFound); } return(accessResult == ContentPermissionsHelper.ContentAccess.Granted); }
/// <summary> /// Ensure the content exists /// </summary> /// <param name="postedItem"></param> /// <param name="actionContext"></param> /// <param name="found"></param> /// <returns></returns> private bool ValidateExistingContent(ContentItemSave postedItem, HttpActionContext actionContext, out ContentItemDto found) { //TODO: We need to of course change this to the real umbraco api found = TestContentService.GetContentItem(postedItem.Id); if (found == null) { var message = string.Format("content with id: {0} was not found", postedItem.Id); actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, message); return false; } return true; }
/// <summary> /// Ensure all of the ids in the post are valid /// </summary> /// <param name="postedItem"></param> /// <param name="actionContext"></param> /// <param name="realItem"></param> /// <returns></returns> private bool ValidateProperties(ContentItemSave postedItem, ContentItemDto realItem, HttpActionContext actionContext) { foreach (var p in postedItem.Properties) { //ensure the property actually exists in our server side properties if (!realItem.Properties.Contains(p)) { //TODO: Do we return errors here ? If someone deletes a property whilst their editing then should we just //save the property data that remains? Or inform them they need to reload... not sure. This problem exists currently too i think. var message = string.Format("property with id: {0} was not found", p.Id); actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, message); return false; } } return true; }