예제 #1
0
        /// <summary>
        /// This will check if any properties of the model are attributed with the RequiredForPersistenceAttribute attribute and if they are it will 
        /// check if that property validates, if it doesn't it means that the current model cannot be persisted because it doesn't have the necessary information
        /// to be saved.
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        /// <remarks>
        /// This is normally used for things like content creating when the name is empty since we cannot actually create a content item when the name is empty.
        /// This is similar but different from the standard Required validator since we still allow content to be saved when validation fails but there are some 
        /// content fields that are absolutely mandatory for creating/saving.
        /// </remarks>
        internal static bool ModelHasRequiredForPersistenceErrors(object model)
        {
            var requiredForPersistenceProperties = TypeDescriptor.GetProperties(model).Cast<PropertyDescriptor>()
                                                                 .Where(x => x.Attributes.Cast<Attribute>().Any(a => a is RequiredForPersistenceAttribute));

            var validator = new RequiredForPersistenceAttribute();
            return requiredForPersistenceProperties.Any(p => !validator.IsValid(p.GetValue(model)));
        }
예제 #2
0
        /// <summary>
        /// This will check if any properties of the model are attributed with the RequiredForPersistenceAttribute attribute and if they are it will
        /// check if that property validates, if it doesn't it means that the current model cannot be persisted because it doesn't have the necessary information
        /// to be saved.
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        /// <remarks>
        /// This is normally used for things like content creating when the name is empty since we cannot actually create a content item when the name is empty.
        /// This is similar but different from the standard Required validator since we still allow content to be saved when validation fails but there are some
        /// content fields that are absolutely mandatory for creating/saving.
        /// </remarks>
        internal static bool ModelHasRequiredForPersistenceErrors(object model)
        {
            var requiredForPersistenceProperties = TypeDescriptor.GetProperties(model).Cast <PropertyDescriptor>()
                                                   .Where(x => x.Attributes.Cast <Attribute>().Any(a => a is RequiredForPersistenceAttribute));

            var validator = new RequiredForPersistenceAttribute();

            return(requiredForPersistenceProperties.Any(p => !validator.IsValid(p.GetValue(model))));
        }
        public ActionResult <MediaItemDisplay> PostSave(
            [ModelBinder(typeof(MediaItemBinder))]
            MediaItemSave contentItem)
        {
            //Recent versions of IE/Edge may send in the full client side file path instead of just the file name.
            //To ensure similar behavior across all browsers no matter what they do - we strip the FileName property of all
            //uploaded files to being *only* the actual file name (as it should be).
            if (contentItem.UploadedFiles != null && contentItem.UploadedFiles.Any())
            {
                foreach (var file in contentItem.UploadedFiles)
                {
                    file.FileName = Path.GetFileName(file.FileName);
                }
            }

            //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

            //Don't update the name if it is empty
            if (contentItem.Name.IsNullOrWhiteSpace() == false)
            {
                contentItem.PersistedContent.Name = contentItem.Name;
            }

            MapPropertyValuesForPersistence <IMedia, MediaItemSave>(
                contentItem,
                contentItem.PropertyCollectionDto,
                (save, property) => property.GetValue(),     //get prop val
                (save, property, v) => property.SetValue(v), //set prop val
                null);                                       // media are all invariant

            //we will continue to save if model state is invalid, however we cannot save if critical data is missing.
            //TODO: Allowing media to be saved when it is invalid is odd - media doesn't have a publish phase so suddenly invalid data is allowed to be 'live'
            if (!ModelState.IsValid)
            {
                //check for critical data validation issues, we can't continue saving if this data is invalid
                if (!RequiredForPersistenceAttribute.HasRequiredValuesForPersistence(contentItem))
                {
                    //ok, so the absolute mandatory data is invalid and it's new, we cannot actually continue!
                    // add the model state to the outgoing object and throw validation response
                    MediaItemDisplay forDisplay = _umbracoMapper.Map <MediaItemDisplay>(contentItem.PersistedContent);
                    return(ValidationProblem(forDisplay, ModelState));
                }
            }

            //save the item
            var saveStatus = _mediaService.Save(contentItem.PersistedContent, _backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId));

            //return the updated model
            var display = _umbracoMapper.Map <MediaItemDisplay>(contentItem.PersistedContent);

            //lastly, if it is not valid, add the model state to the outgoing object and throw a 403
            if (!ModelState.IsValid)
            {
                return(ValidationProblem(display, ModelState, StatusCodes.Status403Forbidden));
            }

            //put the correct msgs in
            switch (contentItem.Action)
            {
            case ContentSaveAction.Save:
            case ContentSaveAction.SaveNew:
                if (saveStatus.Success)
                {
                    display.AddSuccessNotification(
                        _localizedTextService.Localize("speechBubbles", "editMediaSaved"),
                        _localizedTextService.Localize("speechBubbles", "editMediaSavedText"));
                }
                else
                {
                    AddCancelMessage(display);

                    //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 (saveStatus.Result.Result == OperationResultType.FailedCancelledByEvent && IsCreatingAction(contentItem.Action))
                    {
                        return(ValidationProblem(display));
                    }
                }

                break;
            }

            return(display);
        }
예제 #4
0
        public MediaItemDisplay PostSave(
            [ModelBinder(typeof(MediaItemBinder))]
            MediaItemSave contentItem)
        {
            //Recent versions of IE/Edge may send in the full clientside file path instead of just the file name.
            //To ensure similar behavior across all browsers no matter what they do - we strip the FileName property of all
            //uploaded files to being *only* the actual file name (as it should be).
            if (contentItem.UploadedFiles != null && contentItem.UploadedFiles.Any())
            {
                foreach (var file in contentItem.UploadedFiles)
                {
                    file.FileName = Path.GetFileName(file.FileName);
                }
            }

            //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

            //Don't update the name if it is empty
            if (contentItem.Name.IsNullOrWhiteSpace() == false)
            {
                contentItem.PersistedContent.Name = contentItem.Name;
            }

            MapPropertyValuesForPersistence <IMedia, MediaItemSave>(
                contentItem,
                contentItem.PropertyCollectionDto,
                (save, property) => property.GetValue(),     //get prop val
                (save, property, v) => property.SetValue(v), //set prop val
                null);                                       // media are all invariant

            //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 (!RequiredForPersistenceAttribute.HasRequiredValuesForPersistence(contentItem) &&
                    (contentItem.Action == ContentSaveAction.SaveNew))
                {
                    //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 validation response
                    var forDisplay = Mapper.Map <MediaItemDisplay>(contentItem.PersistedContent);
                    forDisplay.Errors = ModelState.ToErrorDictionary();
                    throw new HttpResponseException(Request.CreateValidationErrorResponse(forDisplay));
                }
            }

            //save the item
            var saveStatus = Services.MediaService.Save(contentItem.PersistedContent, (int)Security.CurrentUser.Id);

            //return the updated model
            var display = Mapper.Map <MediaItemDisplay>(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 (saveStatus.Success)
                {
                    display.AddSuccessNotification(
                        Services.TextService.Localize("speechBubbles/editMediaSaved"),
                        Services.TextService.Localize("speechBubbles/editMediaSavedText"));
                }
                else
                {
                    AddCancelMessage(display);

                    //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 (saveStatus.Result.Result == OperationResultType.FailedCancelledByEvent && IsCreatingAction(contentItem.Action))
                    {
                        throw new HttpResponseException(Request.CreateValidationErrorResponse(display));
                    }
                }

                break;
            }

            return(display);
        }