diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/AuthenticateEverythingMiddleware.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/AuthenticateEverythingMiddleware.cs index ab473fd0c0..5031d178bf 100644 --- a/src/Umbraco.Tests/TestHelpers/ControllerTesting/AuthenticateEverythingMiddleware.cs +++ b/src/Umbraco.Tests/TestHelpers/ControllerTesting/AuthenticateEverythingMiddleware.cs @@ -8,6 +8,9 @@ using Umbraco.Core.Security; namespace Umbraco.Tests.TestHelpers.ControllerTesting { + /// + /// Ensures there's an admin user assigned to the request + /// public class AuthenticateEverythingMiddleware : AuthenticationMiddleware { public AuthenticateEverythingMiddleware(OwinMiddleware next, IAppBuilder app, AuthenticationOptions options) @@ -26,7 +29,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting { var sessionId = Guid.NewGuid().ToString(); var identity = new UmbracoBackOfficeIdentity( - -1, "admin", "Admin", null, null, "en-US", sessionId, sessionId, new[] { "content", "media", "members" }, new[] { "admin" }); + -1, "admin", "Admin", new []{-1}, new[] { -1 }, "en-US", sessionId, sessionId, new[] { "content", "media", "members" }, new[] { "admin" }); return Task.FromResult(new AuthenticationTicket(identity, new AuthenticationProperties() diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestRunner.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestRunner.cs index f64e8cb545..64a22926a0 100644 --- a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestRunner.cs +++ b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestRunner.cs @@ -22,8 +22,16 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting _controllerFactory = controllerFactory; } - public async Task> Execute(string controllerName, string actionName, HttpMethod method, HttpContent content = null) + public async Task> Execute(string controllerName, string actionName, HttpMethod method, + HttpContent content = null, + MediaTypeWithQualityHeaderValue mediaTypeHeader = null, + bool assertOkResponse = true) { + if (mediaTypeHeader == null) + { + mediaTypeHeader = new MediaTypeWithQualityHeaderValue("application/json"); + } + var startup = new TestStartup( configuration => { @@ -44,7 +52,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting if (content != null) request.Content = content; - request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + request.Headers.Accept.Add(mediaTypeHeader); Console.WriteLine(request); var response = await server.HttpClient.SendAsync(request); @@ -62,7 +70,11 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting Console.Write(JsonConvert.SerializeObject(deserialized, Formatting.Indented)); } - Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + if (assertOkResponse) + { + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + } + return Tuple.Create(response, json); } } diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index fc70e6ae9e..e842343e96 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -212,6 +212,7 @@ + diff --git a/src/Umbraco.Tests/Web/Controllers/ContentControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/ContentControllerTests.cs new file mode 100644 index 0000000000..d8811c4237 --- /dev/null +++ b/src/Umbraco.Tests/Web/Controllers/ContentControllerTests.cs @@ -0,0 +1,208 @@ +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Web.Http; +using Moq; +using Newtonsoft.Json; +using NUnit.Framework; +using Umbraco.Core.Composing; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Entities; +using Umbraco.Core.Models.Membership; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; +using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.TestHelpers.ControllerTesting; +using Umbraco.Tests.TestHelpers.Entities; +using Umbraco.Tests.Testing; +using Umbraco.Web; +using Umbraco.Web.Editors; +using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.PublishedCache; +using Umbraco.Web._Legacy.Actions; +using Task = System.Threading.Tasks.Task; + +namespace Umbraco.Tests.Web.Controllers +{ + [TestFixture] + [UmbracoTest(Database = UmbracoTestOptions.Database.None)] + public class ContentControllerTests : TestWithDatabaseBase + { + protected override void ComposeApplication(bool withApplication) + { + base.ComposeApplication(withApplication); + + //Replace with mockable services: + + var userServiceMock = new Mock(); + userServiceMock.Setup(service => service.GetUserById(It.IsAny())) + .Returns((int id) => id == 1234 ? new User(1234, "Test", "test@test.com", "test@test.com", "", new List(), new int[0], new int[0]) : null); + userServiceMock.Setup(service => service.GetPermissionsForPath(It.IsAny(), It.IsAny())) + .Returns(new EntityPermissionSet(123, new EntityPermissionCollection(new[] + { + new EntityPermission(0, 123, new[] + { + ActionBrowse.Instance.Letter.ToString(), + ActionUpdate.Instance.Letter.ToString(), + ActionPublish.Instance.Letter.ToString(), + ActionNew.Instance.Letter.ToString() + }), + }))); + + var entityService = new Mock(); + entityService.Setup(x => x.GetAllPaths(UmbracoObjectTypes.Document, It.IsAny())) + .Returns((UmbracoObjectTypes objType, int[] ids) => ids.Select(x => new TreeEntityPath {Path = $"-1,{x}", Id = x}).ToList()); + + var dataTypeService = new Mock(); + dataTypeService.Setup(service => service.GetDataType(It.IsAny())) + .Returns(MockedDataType()); + + Container.RegisterSingleton(f => Mock.Of()); + Container.RegisterSingleton(f => userServiceMock.Object); + Container.RegisterSingleton(f => entityService.Object); + Container.RegisterSingleton(f => dataTypeService.Object); + } + + private IDataType MockedDataType() + { + return Mock.Of(type => type.Id == 9876 && type.Name == "text"); + } + + private MultipartFormDataContent GetMultiPartRequestContent(string json) + { + var multiPartBoundary = "----WebKitFormBoundary123456789"; + return new MultipartFormDataContent(multiPartBoundary) + { + new StringContent(json) + { + Headers = + { + ContentDisposition = new ContentDispositionHeaderValue("form-data") + { + Name = "contentItem" + } + } + } + }; + } + + private const string PublishJson1 = @"{ + ""id"": 123, + ""contentTypeAlias"": ""page"", + ""parentId"": -1, + ""action"": ""save"", + ""variants"": [ + { + ""name"": null, + ""properties"": [ + { + ""id"": 1, + ""alias"": ""title"", + ""value"": ""asdf"" + } + ], + ""culture"": ""en-US"" + }, + { + ""name"": null, + ""properties"": [ + { + ""id"": 1, + ""alias"": ""title"", + ""value"": ""asdf"" + } + ], + ""culture"": ""fr-FR"" + }, + { + ""name"": ""asdf"", + ""properties"": [ + { + ""id"": 1, + ""alias"": ""title"", + ""value"": ""asdf"" + } + ], + ""culture"": ""es-ES"", + ""save"": true, + ""publish"": true + } + ] +}"; + + /// + /// Returns 404 if the content wasn't found based on the ID specified + /// + /// + [Test] + public async Task PostSave_Validate_Existing_Content() + { + ApiController Factory(HttpRequestMessage message, UmbracoHelper helper) + { + //var content = MockedContent.CreateSimpleContent(MockedContentTypes.CreateSimpleContentType()); + //content.Id = 999999999; //this will not be found + //content.Path = "-1,999999999"; + + var contentServiceMock = Mock.Get(Current.Services.ContentService); + contentServiceMock.Setup(x => x.GetById(123)).Returns(() => null); + + var publishedSnapshot = Mock.Of(); + var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); + var usersController = new ContentController(publishedSnapshot, propertyEditorCollection); + Container.InjectProperties(usersController); + return usersController; + } + + var runner = new TestRunner(Factory); + var response = await runner.Execute("Content", "PostSave", HttpMethod.Post, + content: GetMultiPartRequestContent(PublishJson1), + mediaTypeHeader: new MediaTypeWithQualityHeaderValue("multipart/form-data"), + assertOkResponse: false); + + Assert.AreEqual(HttpStatusCode.NotFound, response.Item1.StatusCode); + + //var obj = JsonConvert.DeserializeObject>(response.Item2); + //Assert.AreEqual(0, obj.TotalItems); + } + + /// + /// Returns 404 if any of the posted properties dont actually exist + /// + /// + [Test, Ignore("Not implemented yet")] + public async Task PostSave_Validate_Properties_Exist() + { + //TODO: Make this work! to finish it, we need to include a property in the POST data that doesn't exist on the content type + // or change the content type below to not include one of the posted ones + + ApiController Factory(HttpRequestMessage message, UmbracoHelper helper) + { + var content = MockedContent.CreateSimpleContent(MockedContentTypes.CreateSimpleContentType()); + content.Id = 123; + content.Path = "-1,123"; + + var contentServiceMock = Mock.Get(Current.Services.ContentService); + contentServiceMock.Setup(x => x.GetById(123)).Returns(() => null); + + var publishedSnapshot = Mock.Of(); + var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); + var usersController = new ContentController(publishedSnapshot, propertyEditorCollection); + Container.InjectProperties(usersController); + return usersController; + } + + var runner = new TestRunner(Factory); + var response = await runner.Execute("Content", "PostSave", HttpMethod.Post, + content: GetMultiPartRequestContent(PublishJson1), + mediaTypeHeader: new MediaTypeWithQualityHeaderValue("multipart/form-data"), + assertOkResponse: false); + + Assert.AreEqual(HttpStatusCode.NotFound, response.Item1.StatusCode); + + //var obj = JsonConvert.DeserializeObject>(response.Item2); + //Assert.AreEqual(0, obj.TotalItems); + } + } +} diff --git a/src/Umbraco.Web/Editors/Filters/ContentSaveValidationAttribute.cs b/src/Umbraco.Web/Editors/Filters/ContentSaveValidationAttribute.cs index 8c76ceea3d..40c1138393 100644 --- a/src/Umbraco.Web/Editors/Filters/ContentSaveValidationAttribute.cs +++ b/src/Umbraco.Web/Editors/Filters/ContentSaveValidationAttribute.cs @@ -45,17 +45,14 @@ namespace Umbraco.Web.Editors.Filters var model = (ContentItemSave)actionContext.ActionArguments["contentItem"]; var contentItemValidator = new ContentItemValidationHelper(_logger, _umbracoContextAccessor); - if (ValidateUserAccess(model, actionContext)) + if (!contentItemValidator.ValidateExistingContent(model, actionContext)) return; + if (!ValidateUserAccess(model, actionContext)) return; + + //validate for each variant that is being updated + foreach (var variant in model.Variants.Where(x => x.Save)) { - //now do each validation step - if (contentItemValidator.ValidateExistingContent(model, actionContext) == false) return; - - //validate for each variant that is being updated - foreach (var variant in model.Variants.Where(x => x.Save)) - { - if (contentItemValidator.ValidateProperties(model, variant, actionContext)) - contentItemValidator.ValidatePropertyData(model, variant, variant.PropertyCollectionDto, actionContext.ModelState); - } + if (contentItemValidator.ValidateProperties(model, variant, actionContext)) + contentItemValidator.ValidatePropertyData(model, variant, variant.PropertyCollectionDto, actionContext.ModelState); } }