diff --git a/src/Umbraco.Tests.Integration/Services/ContentServiceEventTests.cs b/src/Umbraco.Tests.Integration/Services/ContentServiceEventTests.cs index 74e71351af..b3cd65dd95 100644 --- a/src/Umbraco.Tests.Integration/Services/ContentServiceEventTests.cs +++ b/src/Umbraco.Tests.Integration/Services/ContentServiceEventTests.cs @@ -20,7 +20,7 @@ namespace Umbraco.Tests.Integration.Services Logger = UmbracoTestOptions.Logger.Console)] public class ContentServiceEventTests : UmbracoIntegrationTest { - private IContentTypeService ContentTypeService => GetRequiredService(); + private IContentTypeService IContentTypeService => GetRequiredService(); private ContentService ContentService => (ContentService)GetRequiredService(); private ILocalizationService LocalizationService => GetRequiredService(); private IFileService FileService => GetRequiredService(); @@ -34,7 +34,7 @@ namespace Umbraco.Tests.Integration.Services ContentRepositoryBase.ThrowOnWarning = true; _globalSettings = new GlobalSettings(); // TODO: remove this once IPublishedSnapShotService has been implemented with nucache. - Umbraco.Core.Services.Implement.ContentTypeService.ClearScopeEvents(); + ContentTypeService.ClearScopeEvents(); CreateTestData(); } @@ -44,7 +44,7 @@ namespace Umbraco.Tests.Integration.Services FileService.SaveTemplate(template); // else, FK violation on contentType! _contentType = ContentTypeBuilder.CreateTextPageContentType(defaultTemplateId: template.Id); - ContentTypeService.Save(_contentType); + IContentTypeService.Save(_contentType); } public override void TearDown() @@ -61,7 +61,7 @@ namespace Umbraco.Tests.Integration.Services _contentType.Variations = ContentVariation.Culture; foreach (var propertyType in _contentType.PropertyTypes) propertyType.Variations = ContentVariation.Culture; - ContentTypeService.Save(_contentType); + IContentTypeService.Save(_contentType); IContent document = new Content("content", -1, _contentType); document.SetCultureName("hello", "en-US"); @@ -155,7 +155,7 @@ namespace Umbraco.Tests.Integration.Services _contentType.Variations = ContentVariation.Culture; foreach (var propertyType in _contentType.PropertyTypes) propertyType.Variations = ContentVariation.Culture; - ContentTypeService.Save(_contentType); + IContentTypeService.Save(_contentType); IContent document = new Content("content", -1, _contentType); document.SetCultureName("hello", "en-US"); @@ -255,7 +255,7 @@ namespace Umbraco.Tests.Integration.Services { var titleProperty = _contentType.PropertyTypes.First(x => x.Alias == "title"); titleProperty.Mandatory = true; // make this required! - ContentTypeService.Save(_contentType); + IContentTypeService.Save(_contentType); IContent document = new Content("content", -1, _contentType); @@ -299,7 +299,7 @@ namespace Umbraco.Tests.Integration.Services _contentType.Variations = ContentVariation.Culture; foreach (var propertyType in _contentType.PropertyTypes) propertyType.Variations = ContentVariation.Culture; - ContentTypeService.Save(_contentType); + IContentTypeService.Save(_contentType); var contentService = (ContentService)ContentService; diff --git a/src/Umbraco.Tests.Integration/Services/MemberServiceTests.cs b/src/Umbraco.Tests.Integration/Services/MemberServiceTests.cs index 1da701bc23..308cfa0599 100644 --- a/src/Umbraco.Tests.Integration/Services/MemberServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/MemberServiceTests.cs @@ -13,6 +13,7 @@ using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; using Umbraco.Tests.Common; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; @@ -27,21 +28,21 @@ namespace Umbraco.Tests.Integration.Services [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true, WithApplication = true)] public class MemberServiceTests : UmbracoIntegrationTest { - private IMemberTypeService MemberTypeService => GetRequiredService(); + private IMemberTypeService IMemberTypeService => GetRequiredService(); private IMemberService MemberService => GetRequiredService(); [SetUp] public void SetupTest() { // TODO: remove this once IPublishedSnapShotService has been implemented with nucache. - Umbraco.Core.Services.Implement.MemberTypeService.ClearScopeEvents(); + MemberTypeService.ClearScopeEvents(); } [Test] public void Can_Update_Member_Property_Value() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); IMember member = MemberBuilder.CreateSimpleMember(memberType, "hello", "helloworld@test123.com", "hello", "hello"); member.SetValue("title", "title of mine"); MemberService.Save(member); @@ -59,7 +60,7 @@ namespace Umbraco.Tests.Integration.Services [Test] public void Can_Get_By_Username() { - var memberType = MemberTypeService.Get("member"); + var memberType = IMemberTypeService.Get("member"); IMember member = new Member("xname", "xemail", "xusername", "xrawpassword", memberType, true); MemberService.Save(member); @@ -73,7 +74,7 @@ namespace Umbraco.Tests.Integration.Services public void Can_Set_Last_Login_Date() { var now = DateTime.Now; - var memberType = MemberTypeService.Get("member"); + var memberType = IMemberTypeService.Get("member"); IMember member = new Member("xname", "xemail", "xusername", "xrawpassword", memberType, true) { LastLoginDate = now, @@ -94,7 +95,7 @@ namespace Umbraco.Tests.Integration.Services [Test] public void Can_Create_Member_With_Properties() { - var memberType = MemberTypeService.Get("member"); + var memberType = IMemberTypeService.Get("member"); IMember member = new Member("xname", "xemail", "xusername", "xrawpassword", memberType, true); MemberService.Save(member); @@ -145,7 +146,7 @@ namespace Umbraco.Tests.Integration.Services public void Can_Create_Member() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); MemberService.Save(member); @@ -159,7 +160,7 @@ namespace Umbraco.Tests.Integration.Services public void Can_Create_Member_With_Long_TLD_In_Email() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.marketing", "pass", "test"); MemberService.Save(member); @@ -218,7 +219,7 @@ namespace Umbraco.Tests.Integration.Services public void Can_Get_All_Roles_By_Member_Id() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); MemberService.Save(member); @@ -236,7 +237,7 @@ namespace Umbraco.Tests.Integration.Services public void Can_Get_All_Roles_Ids_By_Member_Id() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); MemberService.Save(member); @@ -254,7 +255,7 @@ namespace Umbraco.Tests.Integration.Services public void Can_Get_All_Roles_By_Member_Username() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); MemberService.Save(member); //need to test with '@' symbol in the lookup @@ -289,7 +290,7 @@ namespace Umbraco.Tests.Integration.Services public void Throws_When_Deleting_Assigned_Role() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); MemberService.Save(member); @@ -311,7 +312,7 @@ namespace Umbraco.Tests.Integration.Services } IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var member1 = MemberBuilder.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); MemberService.Save(member1); var member2 = MemberBuilder.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); @@ -332,7 +333,7 @@ namespace Umbraco.Tests.Integration.Services public void Cannot_Save_Member_With_Empty_Name() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); IMember member = MemberBuilder.CreateSimpleMember(memberType, string.Empty, "test@test.com", "pass", "test"); // Act & Assert @@ -349,7 +350,7 @@ namespace Umbraco.Tests.Integration.Services public void Find_Members_In_Role(string roleName1, string usernameToMatch, StringPropertyMatchType matchType, int resultCount) { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var member1 = MemberBuilder.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); MemberService.Save(member1); var member2 = MemberBuilder.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); @@ -369,7 +370,7 @@ namespace Umbraco.Tests.Integration.Services MemberService.AddRole("MyTestRole1"); IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var member1 = MemberBuilder.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); MemberService.Save(member1); var member2 = MemberBuilder.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); @@ -392,7 +393,7 @@ namespace Umbraco.Tests.Integration.Services MemberService.AddRole("MyTestRole1"); IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var member1 = MemberBuilder.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); MemberService.Save(member1); var member2 = MemberBuilder.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); @@ -415,7 +416,7 @@ namespace Umbraco.Tests.Integration.Services MemberService.AddRole("MyTestRole1"); IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var member1 = MemberBuilder.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); MemberService.Save(member1); var member2 = MemberBuilder.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); @@ -434,7 +435,7 @@ namespace Umbraco.Tests.Integration.Services MemberService.AddRole("MyTestRole1"); IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var member1 = MemberBuilder.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1@test.com"); MemberService.Save(member1); var member2 = MemberBuilder.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2@test.com"); @@ -451,7 +452,7 @@ namespace Umbraco.Tests.Integration.Services public void Associate_Members_To_Roles_With_New_Role() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var member1 = MemberBuilder.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); MemberService.Save(member1); var member2 = MemberBuilder.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); @@ -469,7 +470,7 @@ namespace Umbraco.Tests.Integration.Services public void Remove_Members_From_Roles_With_Member_Id() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var member1 = MemberBuilder.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); MemberService.Save(member1); var member2 = MemberBuilder.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); @@ -490,7 +491,7 @@ namespace Umbraco.Tests.Integration.Services public void Remove_Members_From_Roles_With_Member_Username() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var member1 = MemberBuilder.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); MemberService.Save(member1); var member2 = MemberBuilder.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); @@ -511,7 +512,7 @@ namespace Umbraco.Tests.Integration.Services public void Can_Delete_member() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); MemberService.Save(member); @@ -526,7 +527,7 @@ namespace Umbraco.Tests.Integration.Services public void Exists_By_Username() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); MemberService.Save(member); IMember member2 = MemberBuilder.CreateSimpleMember(memberType, "test", "test2@test.com", "pass", "test2@test.com"); @@ -541,7 +542,7 @@ namespace Umbraco.Tests.Integration.Services public void Exists_By_Id() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); MemberService.Save(member); @@ -553,7 +554,7 @@ namespace Umbraco.Tests.Integration.Services public void Tracks_Dirty_Changes() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); MemberService.Save(member); @@ -577,7 +578,7 @@ namespace Umbraco.Tests.Integration.Services public void Get_By_Email() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); MemberService.Save(member); @@ -589,7 +590,7 @@ namespace Umbraco.Tests.Integration.Services public void Get_Member_Name() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); IMember member = MemberBuilder.CreateSimpleMember(memberType, "Test Real Name", "test@test.com", "pass", "testUsername"); MemberService.Save(member); @@ -601,7 +602,7 @@ namespace Umbraco.Tests.Integration.Services public void Get_By_Username() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); MemberService.Save(member); @@ -613,7 +614,7 @@ namespace Umbraco.Tests.Integration.Services public void Get_By_Object_Id() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); MemberService.Save(member); @@ -625,7 +626,7 @@ namespace Umbraco.Tests.Integration.Services public void Get_All_Paged_Members() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); MemberService.Save(members); @@ -642,7 +643,7 @@ namespace Umbraco.Tests.Integration.Services public void Get_All_Paged_Members_With_Filter() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); MemberService.Save(members); @@ -665,7 +666,7 @@ namespace Umbraco.Tests.Integration.Services public void Find_By_Name_Starts_With() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); MemberService.Save(members); @@ -682,7 +683,7 @@ namespace Umbraco.Tests.Integration.Services public void Find_By_Email_Starts_With() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); MemberService.Save(members); //don't find this @@ -699,7 +700,7 @@ namespace Umbraco.Tests.Integration.Services public void Find_By_Email_Ends_With() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); MemberService.Save(members); //include this @@ -716,7 +717,7 @@ namespace Umbraco.Tests.Integration.Services public void Find_By_Email_Contains() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); MemberService.Save(members); //include this @@ -733,7 +734,7 @@ namespace Umbraco.Tests.Integration.Services public void Find_By_Email_Exact() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); MemberService.Save(members); //include this @@ -750,7 +751,7 @@ namespace Umbraco.Tests.Integration.Services public void Find_By_Login_Starts_With() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); MemberService.Save(members); //don't find this @@ -767,7 +768,7 @@ namespace Umbraco.Tests.Integration.Services public void Find_By_Login_Ends_With() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); MemberService.Save(members); //include this @@ -784,7 +785,7 @@ namespace Umbraco.Tests.Integration.Services public void Find_By_Login_Contains() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); MemberService.Save(members); //include this @@ -801,7 +802,7 @@ namespace Umbraco.Tests.Integration.Services public void Find_By_Login_Exact() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); MemberService.Save(members); //include this @@ -818,7 +819,7 @@ namespace Umbraco.Tests.Integration.Services public void Get_By_Property_String_Value_Exact() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); MemberService.Save(members); var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); @@ -834,7 +835,7 @@ namespace Umbraco.Tests.Integration.Services public void Get_By_Property_String_Value_Contains() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); MemberService.Save(members); var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); @@ -850,7 +851,7 @@ namespace Umbraco.Tests.Integration.Services public void Get_By_Property_String_Value_Starts_With() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); MemberService.Save(members); var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); @@ -866,7 +867,7 @@ namespace Umbraco.Tests.Integration.Services public void Get_By_Property_String_Value_Ends_With() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); MemberService.Save(members); var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); @@ -889,7 +890,7 @@ namespace Umbraco.Tests.Integration.Services //NOTE: This is what really determines the db type - the above definition doesn't really do anything DataTypeId = -51 }, "Content"); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.SetValue("number", i)); MemberService.Save(members); @@ -913,7 +914,7 @@ namespace Umbraco.Tests.Integration.Services //NOTE: This is what really determines the db type - the above definition doesn't really do anything DataTypeId = -51 }, "Content"); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.SetValue("number", i)); MemberService.Save(members); @@ -937,7 +938,7 @@ namespace Umbraco.Tests.Integration.Services //NOTE: This is what really determines the db type - the above definition doesn't really do anything DataTypeId = -51 }, "Content"); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.SetValue("number", i)); MemberService.Save(members); @@ -961,7 +962,7 @@ namespace Umbraco.Tests.Integration.Services //NOTE: This is what really determines the db type - the above definition doesn't really do anything DataTypeId = -51 }, "Content"); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.SetValue("number", i)); MemberService.Save(members); @@ -985,7 +986,7 @@ namespace Umbraco.Tests.Integration.Services //NOTE: This is what really determines the db type - the above definition doesn't really do anything DataTypeId = -51 }, "Content"); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.SetValue("number", i)); MemberService.Save(members); @@ -1009,7 +1010,7 @@ namespace Umbraco.Tests.Integration.Services //NOTE: This is what really determines the db type - the above definition doesn't really do anything DataTypeId = -36 }, "Content"); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.SetValue("date", new DateTime(2013, 12, 20, 1, i, 0))); MemberService.Save(members); @@ -1033,7 +1034,7 @@ namespace Umbraco.Tests.Integration.Services //NOTE: This is what really determines the db type - the above definition doesn't really do anything DataTypeId = -36 }, "Content"); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.SetValue("date", new DateTime(2013, 12, 20, 1, i, 0))); MemberService.Save(members); @@ -1057,7 +1058,7 @@ namespace Umbraco.Tests.Integration.Services //NOTE: This is what really determines the db type - the above definition doesn't really do anything DataTypeId = -36 }, "Content"); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.SetValue("date", new DateTime(2013, 12, 20, 1, i, 0))); MemberService.Save(members); @@ -1081,7 +1082,7 @@ namespace Umbraco.Tests.Integration.Services //NOTE: This is what really determines the db type - the above definition doesn't really do anything DataTypeId = -36 }, "Content"); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.SetValue("date", new DateTime(2013, 12, 20, 1, i, 0))); MemberService.Save(members); @@ -1105,7 +1106,7 @@ namespace Umbraco.Tests.Integration.Services //NOTE: This is what really determines the db type - the above definition doesn't really do anything DataTypeId = -36 }, "Content"); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.SetValue("date", new DateTime(2013, 12, 20, 1, i, 0))); MemberService.Save(members); @@ -1123,7 +1124,7 @@ namespace Umbraco.Tests.Integration.Services public void Count_All_Members() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); MemberService.Save(members); var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); @@ -1138,7 +1139,7 @@ namespace Umbraco.Tests.Integration.Services public void Count_All_Locked_Members() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.IsLockedOut = i % 2 == 0); MemberService.Save(members); @@ -1155,7 +1156,7 @@ namespace Umbraco.Tests.Integration.Services public void Count_All_Approved_Members() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.IsApproved = i % 2 == 0); MemberService.Save(members); @@ -1172,9 +1173,9 @@ namespace Umbraco.Tests.Integration.Services public void Setting_Property_On_Built_In_Member_Property_When_Property_Doesnt_Exist_On_Type_Is_Ok() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); memberType.RemovePropertyType(Constants.Conventions.Member.Comments); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); Assert.IsFalse(memberType.PropertyTypes.Any(x => x.Alias == Constants.Conventions.Member.Comments)); var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); @@ -1195,7 +1196,7 @@ namespace Umbraco.Tests.Integration.Services public void Setting_DateTime_Property_On_Built_In_Member_Property_Saves_To_Correct_Column() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "test", "test"); var date = DateTime.Now; member.LastLoginDate = DateTime.Now; @@ -1233,7 +1234,7 @@ namespace Umbraco.Tests.Integration.Services public void New_Member_Approved_By_Default() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); MemberService.Save(customMember); diff --git a/src/Umbraco.Tests.Integration/Services/MemberTypeServiceTests.cs b/src/Umbraco.Tests.Integration/Services/MemberTypeServiceTests.cs index 3c269080a5..65ab6557de 100644 --- a/src/Umbraco.Tests.Integration/Services/MemberTypeServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/MemberTypeServiceTests.cs @@ -5,6 +5,7 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; @@ -17,22 +18,22 @@ namespace Umbraco.Tests.Integration.Services public class MemberTypeServiceTests : UmbracoIntegrationTest { private IMemberService MemberService => GetRequiredService(); - private IMemberTypeService MemberTypeService => GetRequiredService(); + private IMemberTypeService IMemberTypeService => GetRequiredService(); [SetUp] public void SetupTest() { // TODO: remove this once IPublishedSnapShotService has been implemented with nucache. - Umbraco.Core.Services.Implement.MemberTypeService.ClearScopeEvents(); + MemberTypeService.ClearScopeEvents(); } [Test] public void Member_Cannot_Edit_Property() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); //re-get - memberType = MemberTypeService.Get(memberType.Id); + memberType = IMemberTypeService.Get(memberType.Id); foreach (var p in memberType.PropertyTypes) { Assert.IsFalse(memberType.MemberCanEditProperty(p.Alias)); @@ -43,12 +44,12 @@ namespace Umbraco.Tests.Integration.Services public void Member_Can_Edit_Property() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var prop = memberType.PropertyTypes.First().Alias; memberType.SetMemberCanEditProperty(prop, true); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); //re-get - memberType = MemberTypeService.Get(memberType.Id); + memberType = IMemberTypeService.Get(memberType.Id); foreach (var p in memberType.PropertyTypes.Where(x => x.Alias != prop)) { Assert.IsFalse(memberType.MemberCanEditProperty(p.Alias)); @@ -60,9 +61,9 @@ namespace Umbraco.Tests.Integration.Services public void Member_Cannot_View_Property() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); //re-get - memberType = MemberTypeService.Get(memberType.Id); + memberType = IMemberTypeService.Get(memberType.Id); foreach (var p in memberType.PropertyTypes) { Assert.IsFalse(memberType.MemberCanViewProperty(p.Alias)); @@ -73,12 +74,12 @@ namespace Umbraco.Tests.Integration.Services public void Member_Can_View_Property() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); var prop = memberType.PropertyTypes.First().Alias; memberType.SetMemberCanViewProperty(prop, true); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); //re-get - memberType = MemberTypeService.Get(memberType.Id); + memberType = IMemberTypeService.Get(memberType.Id); foreach (var p in memberType.PropertyTypes.Where(x => x.Alias != prop)) { Assert.IsFalse(memberType.MemberCanViewProperty(p.Alias)); @@ -90,7 +91,7 @@ namespace Umbraco.Tests.Integration.Services public void Deleting_PropertyType_Removes_The_Property_From_Member() { IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); MemberService.Save(member); var initProps = member.Properties.Count; @@ -98,7 +99,7 @@ namespace Umbraco.Tests.Integration.Services //remove a property (NOT ONE OF THE DEFAULTS) var standardProps = ConventionsHelper.GetStandardPropertyTypeStubs(ShortStringHelper); memberType.RemovePropertyType(memberType.PropertyTypes.First(x => standardProps.ContainsKey(x.Alias) == false).Alias); - MemberTypeService.Save(memberType); + IMemberTypeService.Save(memberType); //re-load it from the db member = MemberService.GetById(member.Id); @@ -113,13 +114,13 @@ namespace Umbraco.Tests.Integration.Services IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType("memberTypeAlias", string.Empty); // Act & Assert - Assert.Throws(() => MemberTypeService.Save(memberType)); + Assert.Throws(() => IMemberTypeService.Save(memberType)); } [Test] public void Empty_Description_Is_Always_Null_After_Saving_Member_Type() { - var service = MemberTypeService; + var service = IMemberTypeService; var memberType = MemberTypeBuilder.CreateSimpleMemberType(); memberType.Description = null; service.Save(memberType); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/RenderIndexActionSelectorAttributeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/RenderIndexActionSelectorAttributeTests.cs new file mode 100644 index 0000000000..3a987fb038 --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/RenderIndexActionSelectorAttributeTests.cs @@ -0,0 +1,168 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.AspNetCore.Mvc.ViewEngines; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Moq; +using NUnit.Framework; +using Umbraco.Web.Models; +using Umbraco.Web.Mvc; + +namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers +{ + [TestFixture] + public class RenderIndexActionSelectorAttributeTests + { + [Test] + public void IsValidForRequest__ensure_caching_works() + { + var sut = new RenderIndexActionSelectorAttribute(); + + var actionDescriptor = + GetRenderMvcControllerIndexMethodFromCurrentType(typeof(MatchesDefaultIndexController)).First(); + var actionDescriptorCollectionProviderMock = new Mock(); + actionDescriptorCollectionProviderMock.Setup(x => x.ActionDescriptors) + .Returns(new ActionDescriptorCollection(Array.Empty(), 1)); + + var routeContext = CreateRouteContext(actionDescriptorCollectionProviderMock.Object); + + // Call the method multiple times + for (var i = 0; i < 1; i++) + { + sut.IsValidForRequest(routeContext, actionDescriptor); + } + + //Ensure the underlying ActionDescriptors is only called once. + actionDescriptorCollectionProviderMock.Verify(x=>x.ActionDescriptors, Times.Once); + } + + [Test] + [TestCase(typeof(MatchesDefaultIndexController), + "Index", new[] { typeof(ContentModel) }, typeof(IActionResult), ExpectedResult = true)] + [TestCase(typeof(MatchesOverriddenIndexController), + "Index", new[] { typeof(ContentModel) }, typeof(IActionResult), ExpectedResult = true)] + [TestCase(typeof(MatchesCustomIndexController), + "Index", new[] { typeof(ContentModel), typeof(int) }, typeof(IActionResult), ExpectedResult = false)] + [TestCase(typeof(MatchesAsyncIndexController), + "Index", new[] { typeof(ContentModel) }, typeof(Task), ExpectedResult = false)] + public bool IsValidForRequest__must_return_the_expected_result(Type controllerType, string actionName, Type[] parameterTypes, Type returnType) + { + //Fake all IActionDescriptor's that will be returned by IActionDescriptorCollectionProvider + var actionDescriptors = GetRenderMvcControllerIndexMethodFromCurrentType(controllerType); + + // Find the one that match the current request + var actualActionDescriptor = actionDescriptors.Single(x => x.ActionName == actionName + && x.ControllerTypeInfo.Name == controllerType.Name + && x.MethodInfo.ReturnType == returnType + && x.MethodInfo.GetParameters().Select(m => m.ParameterType).SequenceEqual(parameterTypes)); + + //Fake the IActionDescriptorCollectionProvider and add it to the service collection on httpcontext + var sut = new RenderIndexActionSelectorAttribute(); + + var routeContext = CreateRouteContext(new TestActionDescriptorCollectionProvider(actionDescriptors)); + + //Act + var result = sut.IsValidForRequest(routeContext, actualActionDescriptor); + return result; + } + + private ControllerActionDescriptor[] GetRenderMvcControllerIndexMethodFromCurrentType(Type controllerType) + { + var actions = controllerType.GetMethods(BindingFlags.Public | BindingFlags.Instance) + .Where(m => !m.IsSpecialName + && m.GetCustomAttribute() is null + && m.Module.Name.Contains("Umbraco")); + + var actionDescriptors = actions + .Select(x => new ControllerActionDescriptor() + { + ControllerTypeInfo = controllerType.GetTypeInfo(), + ActionName = x.Name, + MethodInfo = x + }).ToArray(); + + return actionDescriptors; + } + + private static RouteContext CreateRouteContext(IActionDescriptorCollectionProvider actionDescriptorCollectionProvider) + { + //Fake the IActionDescriptorCollectionProvider and add it to the service collection on httpcontext + var httpContext = new DefaultHttpContext(); + var serviceCollection = new ServiceCollection(); + serviceCollection.AddSingleton(actionDescriptorCollectionProvider); + httpContext.RequestServices = + new DefaultServiceProviderFactory(new ServiceProviderOptions()) + .CreateServiceProvider(serviceCollection); + + // Put the fake httpcontext on the route context. + var routeContext = new RouteContext(httpContext); + return routeContext; + } + + private class TestActionDescriptorCollectionProvider : IActionDescriptorCollectionProvider + { + public TestActionDescriptorCollectionProvider(IReadOnlyList items) + { + ActionDescriptors = new ActionDescriptorCollection(items, 1); + } + + public ActionDescriptorCollection ActionDescriptors { get; } + } + + private class MatchesDefaultIndexController : RenderMvcController + { + public MatchesDefaultIndexController(ILogger logger, + ICompositeViewEngine compositeViewEngine) : base(logger, compositeViewEngine) + { + } + } + + private class MatchesOverriddenIndexController : RenderMvcController + { + public override IActionResult Index(ContentModel model) + { + return base.Index(model); + } + + public MatchesOverriddenIndexController(ILogger logger, + ICompositeViewEngine compositeViewEngine) : base(logger, compositeViewEngine) + { + } + } + + private class MatchesCustomIndexController : RenderMvcController + { + public IActionResult Index(ContentModel model, int page) + { + return base.Index(model); + } + + public MatchesCustomIndexController(ILogger logger, + ICompositeViewEngine compositeViewEngine) : base(logger, compositeViewEngine) + { + } + } + + private class MatchesAsyncIndexController : RenderMvcController + { + public new async Task Index(ContentModel model) + { + return await Task.FromResult(base.Index(model)); + } + + public MatchesAsyncIndexController(ILogger logger, + ICompositeViewEngine compositeViewEngine) : base(logger, compositeViewEngine) + { + } + } + } +} diff --git a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs index 2262499347..d74a8c68fe 100644 --- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs +++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs @@ -198,7 +198,7 @@ namespace Umbraco.Tests.Routing public class CustomDocumentController : RenderMvcController { public CustomDocumentController(IOptions globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, ILoggerFactory loggerFactory) - : base(globalSettings, umbracoContextAccessor, services, appCaches, profilingLogger, loggerFactory) + { } diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 2e87628612..8c56a05169 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -221,7 +221,6 @@ - diff --git a/src/Umbraco.Tests/Web/Mvc/RenderIndexActionSelectorAttributeTests.cs b/src/Umbraco.Tests/Web/Mvc/RenderIndexActionSelectorAttributeTests.cs deleted file mode 100644 index bd9b646872..0000000000 --- a/src/Umbraco.Tests/Web/Mvc/RenderIndexActionSelectorAttributeTests.cs +++ /dev/null @@ -1,216 +0,0 @@ -using System; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; -using System.Web; -using System.Web.Mvc; -using System.Web.Routing; -using Moq; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Logging; -using Umbraco.Core.Services; -using Umbraco.Tests.Common; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.TestHelpers.Stubs; -using Umbraco.Web; -using Umbraco.Web.Models; -using Umbraco.Web.Mvc; -using Umbraco.Web.PublishedCache; -using Umbraco.Web.Routing; -using Umbraco.Web.Security; -using Current = Umbraco.Web.Composing.Current; - -namespace Umbraco.Tests.Web.Mvc -{ - [TestFixture] - public class RenderIndexActionSelectorAttributeTests - { - [SetUp] - public void SetUp() - { - Current.UmbracoContextAccessor = new TestUmbracoContextAccessor(); - Current.Factory = Mock.Of(); - } - - [TearDown] - public void TearDown() - { - Current.Reset(); - } - - private TestObjects TestObjects = new TestObjects(null); - - private MethodInfo GetRenderMvcControllerIndexMethodFromCurrentType(Type currType) - { - return currType.GetMethods().Single(x => - { - if (x.Name != "Index") return false; - if (x.ReturnParameter == null || x.ReturnParameter.ParameterType != typeof (ActionResult)) return false; - var p = x.GetParameters(); - if (p.Length != 1) return false; - if (p[0].ParameterType != typeof (ContentModel)) return false; - return true; - }); - } - - [Test] - public void Matches_Default_Index() - { - var globalSettings = TestObjects.GetGlobalSettings(); - var attr = new RenderIndexActionSelectorAttribute(); - var req = new RequestContext(); - var httpContextAccessor = TestHelper.GetHttpContextAccessor(); - - var umbracoContextFactory = new UmbracoContextFactory( - Current.UmbracoContextAccessor, - Mock.Of(), - new TestVariationContextAccessor(), - new TestDefaultCultureAccessor(), - globalSettings, - Mock.Of(), - TestHelper.GetHostingEnvironment(), - TestHelper.UriUtility, - httpContextAccessor, - new AspNetCookieManager(httpContextAccessor)); - - var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); - var umbCtx = umbracoContextReference.UmbracoContext; - - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbCtx); - var ctrl = new MatchesDefaultIndexController { UmbracoContextAccessor = umbracoContextAccessor }; - var controllerCtx = new ControllerContext(req, ctrl); - var result = attr.IsValidForRequest(controllerCtx, - GetRenderMvcControllerIndexMethodFromCurrentType(ctrl.GetType())); - - Assert.IsTrue(result); - } - - [Test] - public void Matches_Overriden_Index() - { - var globalSettings = TestObjects.GetGlobalSettings(); - var attr = new RenderIndexActionSelectorAttribute(); - var req = new RequestContext(); - var httpContextAccessor = TestHelper.GetHttpContextAccessor(); - - var umbracoContextFactory = new UmbracoContextFactory( - Current.UmbracoContextAccessor, - Mock.Of(), - new TestVariationContextAccessor(), - new TestDefaultCultureAccessor(), - globalSettings, - Mock.Of(), - TestHelper.GetHostingEnvironment(), - TestHelper.UriUtility, - httpContextAccessor, - new AspNetCookieManager(httpContextAccessor)); - - var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); - var umbCtx = umbracoContextReference.UmbracoContext; - - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbCtx); - var ctrl = new MatchesOverriddenIndexController { UmbracoContextAccessor = umbracoContextAccessor }; - var controllerCtx = new ControllerContext(req, ctrl); - var result = attr.IsValidForRequest(controllerCtx, - GetRenderMvcControllerIndexMethodFromCurrentType(ctrl.GetType())); - - Assert.IsTrue(result); - } - - [Test] - public void Matches_Custom_Index() - { - var globalSettings = TestObjects.GetGlobalSettings(); - var attr = new RenderIndexActionSelectorAttribute(); - var req = new RequestContext(); - var httpContextAccessor = TestHelper.GetHttpContextAccessor(); - - var umbracoContextFactory = new UmbracoContextFactory( - Current.UmbracoContextAccessor, - Mock.Of(), - new TestVariationContextAccessor(), - new TestDefaultCultureAccessor(), - globalSettings, - Mock.Of(), - TestHelper.GetHostingEnvironment(), - TestHelper.UriUtility, - httpContextAccessor, - new AspNetCookieManager(httpContextAccessor)); - - var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); - var umbCtx = umbracoContextReference.UmbracoContext; - - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbCtx); - var ctrl = new MatchesCustomIndexController { UmbracoContextAccessor = umbracoContextAccessor }; - var controllerCtx = new ControllerContext(req, ctrl); - var result = attr.IsValidForRequest(controllerCtx, - GetRenderMvcControllerIndexMethodFromCurrentType(ctrl.GetType())); - - Assert.IsFalse(result); - } - - [Test] - public void Matches_Async_Index_Same_Signature() - { - var globalSettings = TestObjects.GetGlobalSettings(); - var attr = new RenderIndexActionSelectorAttribute(); - var req = new RequestContext(); - var httpContextAccessor = TestHelper.GetHttpContextAccessor(); - - var umbracoContextFactory = new UmbracoContextFactory( - Current.UmbracoContextAccessor, - Mock.Of(), - new TestVariationContextAccessor(), - new TestDefaultCultureAccessor(), - globalSettings, - Mock.Of(), - TestHelper.GetHostingEnvironment(), - TestHelper.UriUtility, - httpContextAccessor, - new AspNetCookieManager(httpContextAccessor)); - - var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); - var umbCtx = umbracoContextReference.UmbracoContext; - - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbCtx); - var ctrl = new MatchesAsyncIndexController { UmbracoContextAccessor = umbracoContextAccessor }; - var controllerCtx = new ControllerContext(req, ctrl); - var result = attr.IsValidForRequest(controllerCtx, - GetRenderMvcControllerIndexMethodFromCurrentType(ctrl.GetType())); - - Assert.IsFalse(result); - } - - public class MatchesDefaultIndexController : RenderMvcController - { - } - - public class MatchesOverriddenIndexController : RenderMvcController - { - public override ActionResult Index(ContentModel model) - { - return base.Index(model); - } - } - - public class MatchesCustomIndexController : RenderMvcController - { - public ActionResult Index(ContentModel model, int page) - { - return base.Index(model); - } - } - - public class MatchesAsyncIndexController : RenderMvcController - { - public new async Task Index(ContentModel model) - { - return await Task.FromResult(base.Index(model)); - } - } - } -} diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs index 7a8adca44f..b87b5d0fbb 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs @@ -26,16 +26,15 @@ using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Filters; using Umbraco.Web.Common.Security; using Umbraco.Web.Models; -using Umbraco.Web.Security; +using Umbraco.Web.Mvc; using Umbraco.Web.WebAssets; using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.BackOffice.Controllers { //[UmbracoRequireHttps] //TODO Reintroduce - [DisableBrowserCache] [PluginController(Constants.Web.Mvc.BackOfficeArea)] - public class BackOfficeController : Controller + public class BackOfficeController : UmbracoController { private readonly IBackOfficeUserManager _userManager; private readonly IRuntimeMinifier _runtimeMinifier; diff --git a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs index 96f0689b52..0a3d3c47a7 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs @@ -29,14 +29,13 @@ using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Routing; using Constants = Umbraco.Core.Constants; using Umbraco.Extensions; -using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.BackOffice.ModelBinders; using Umbraco.Web.Common.ActionResults; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Exceptions; +using Umbraco.Web.Common.Filters; using Umbraco.Web.Models.Mapping; -using Umbraco.Web.Security; using Umbraco.Web.WebApi.Filters; namespace Umbraco.Web.BackOffice.Controllers diff --git a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs index 8efe13782a..0254021b40 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs @@ -24,9 +24,9 @@ using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.BackOffice.Security; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Exceptions; +using Umbraco.Web.Common.Filters; using Umbraco.Web.Models; using Umbraco.Web.Models.ContentEditing; -using Umbraco.Web.Security; namespace Umbraco.Web.BackOffice.Controllers { diff --git a/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs index 5b4876baca..2725e1b7a6 100644 --- a/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs @@ -6,6 +6,8 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System; using Umbraco.Extensions; +using Umbraco.Web.Common.Filters; +using Umbraco.Web.Common.ModelBinders; namespace Umbraco.Web.Common.Builder { @@ -38,11 +40,19 @@ namespace Umbraco.Web.Common.Builder public static IUmbracoBuilder WithMvcAndRazor(this IUmbracoBuilder builder, Action mvcOptions = null, Action mvcBuilding = null) => builder.AddWith(nameof(WithMvcAndRazor), () => { + + // TODO: We need to figure out if we can work around this because calling AddControllersWithViews modifies the global app and order is very important // this will directly affect developers who need to call that themselves. //We need to have runtime compilation of views when using umbraco. We could consider having only this when a specific config is set. //But as far as I can see, there are still precompiled views, even when this is activated, so maybe it is okay. - var mvcBuilder = builder.Services.AddControllersWithViews(mvcOptions).AddRazorRuntimeCompilation(); + var mvcBuilder = builder.Services.AddControllersWithViews(options => + { + options.ModelBinderProviders.Insert(0, new ContentModelBinderProvider()); + + options.Filters.Insert(0, new EnsurePartialViewMacroViewContextFilterAttribute()); + mvcOptions?.Invoke(options); + }).AddRazorRuntimeCompilation(); mvcBuilding?.Invoke(mvcBuilder); }); diff --git a/src/Umbraco.Web/Mvc/IRenderController.cs b/src/Umbraco.Web.Common/Controllers/IRenderController.cs similarity index 67% rename from src/Umbraco.Web/Mvc/IRenderController.cs rename to src/Umbraco.Web.Common/Controllers/IRenderController.cs index 0de585959c..3eaf1c35c3 100644 --- a/src/Umbraco.Web/Mvc/IRenderController.cs +++ b/src/Umbraco.Web.Common/Controllers/IRenderController.cs @@ -1,12 +1,10 @@ -using System.Web.Mvc; - -namespace Umbraco.Web.Mvc +namespace Umbraco.Web.Mvc { /// /// A marker interface to designate that a controller will be used for Umbraco front-end requests and/or route hijacking /// /// Migrated already to .Net Core - public interface IRenderController : IController + public interface IRenderController { } diff --git a/src/Umbraco.Web.Common/Controllers/IRenderMvcController.cs b/src/Umbraco.Web.Common/Controllers/IRenderMvcController.cs new file mode 100644 index 0000000000..8727918bf4 --- /dev/null +++ b/src/Umbraco.Web.Common/Controllers/IRenderMvcController.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Mvc; +using Umbraco.Core.Composing; +using Umbraco.Web.Models; + +namespace Umbraco.Web.Mvc +{ + /// + /// The interface that must be implemented for a controller to be designated to execute for route hijacking + /// + public interface IRenderMvcController : IRenderController, IDiscoverable + { + /// + /// The default action to render the front-end view + /// + /// + /// + IActionResult Index(ContentModel model); + } +} diff --git a/src/Umbraco.Web.Common/Controllers/RenderController.cs b/src/Umbraco.Web.Common/Controllers/RenderController.cs index 43058616de..b95859ccbe 100644 --- a/src/Umbraco.Web.Common/Controllers/RenderController.cs +++ b/src/Umbraco.Web.Common/Controllers/RenderController.cs @@ -1,8 +1,9 @@ using Microsoft.AspNetCore.Mvc; +using Umbraco.Web.Mvc; namespace Umbraco.Web.Common.Controllers { - public abstract class RenderController : Controller + public abstract class RenderController : Controller, IRenderController { } diff --git a/src/Umbraco.Web.Common/Controllers/UmbracoController.cs b/src/Umbraco.Web.Common/Controllers/UmbracoController.cs new file mode 100644 index 0000000000..1498b2c75c --- /dev/null +++ b/src/Umbraco.Web.Common/Controllers/UmbracoController.cs @@ -0,0 +1,23 @@ +using System; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Umbraco.Composing; +using Umbraco.Core.Cache; +using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Services; +using Umbraco.Web.Security; + +namespace Umbraco.Web.Mvc +{ + /// + /// Provides a base class for Umbraco controllers. + /// + public abstract class UmbracoController : Controller + { + // for debugging purposes + internal Guid InstanceId { get; } = Guid.NewGuid(); + + } +} diff --git a/src/Umbraco.Web.Common/Filters/EnsurePartialViewMacroViewContextFilterAttribute.cs b/src/Umbraco.Web.Common/Filters/EnsurePartialViewMacroViewContextFilterAttribute.cs index 269e437d0d..360396fe04 100644 --- a/src/Umbraco.Web.Common/Filters/EnsurePartialViewMacroViewContextFilterAttribute.cs +++ b/src/Umbraco.Web.Common/Filters/EnsurePartialViewMacroViewContextFilterAttribute.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Mvc.ViewEngines; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Umbraco.Web.Common.Constants; using Umbraco.Web.Common.Controllers; +using Umbraco.Web.Mvc; namespace Umbraco.Web.Common.Filters { @@ -28,7 +29,7 @@ namespace Umbraco.Web.Common.Filters /// public class EnsurePartialViewMacroViewContextFilterAttribute : ActionFilterAttribute { - + /// /// Ensures the custom ViewContext datatoken is set before the RenderController action is invoked, /// this ensures that any calls to GetPropertyValue with regards to RTE or Grid editors can still @@ -40,7 +41,7 @@ namespace Umbraco.Web.Common.Filters if (!(context.Controller is Controller controller)) return; //ignore anything that is not IRenderController - if (!(controller is RenderController)) return; + if (!(controller is IRenderController)) return; SetViewContext(context, controller); } diff --git a/src/Umbraco.Web.Common/Filters/ModelBindingExceptionFilter.cs b/src/Umbraco.Web.Common/Filters/ModelBindingExceptionFilter.cs index 3c1de1e138..6cec04e0b6 100644 --- a/src/Umbraco.Web.Common/Filters/ModelBindingExceptionFilter.cs +++ b/src/Umbraco.Web.Common/Filters/ModelBindingExceptionFilter.cs @@ -19,7 +19,7 @@ namespace Umbraco.Web.Common.Filters /// /// This is only enabled when running PureLive /// - internal class ModelBindingExceptionFilter : ActionFilterAttribute, IExceptionFilter + public class ModelBindingExceptionFilter : ActionFilterAttribute, IExceptionFilter { private static readonly Regex _getPublishedModelsTypesRegex = new Regex("Umbraco.Web.PublishedModels.(\\w+)", RegexOptions.Compiled); diff --git a/src/Umbraco.Web.BackOffice/Filters/UmbracoAuthorizeAttribute.cs b/src/Umbraco.Web.Common/Filters/UmbracoAuthorizeAttribute.cs similarity index 96% rename from src/Umbraco.Web.BackOffice/Filters/UmbracoAuthorizeAttribute.cs rename to src/Umbraco.Web.Common/Filters/UmbracoAuthorizeAttribute.cs index a4b47522ee..8a7c7b04d5 100644 --- a/src/Umbraco.Web.BackOffice/Filters/UmbracoAuthorizeAttribute.cs +++ b/src/Umbraco.Web.Common/Filters/UmbracoAuthorizeAttribute.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Mvc; -namespace Umbraco.Web.BackOffice.Filters +namespace Umbraco.Web.Common.Filters { /// /// Ensures authorization is successful for a back office user. diff --git a/src/Umbraco.Web.BackOffice/Filters/UmbracoAuthorizeFilter.cs b/src/Umbraco.Web.Common/Filters/UmbracoAuthorizeFilter.cs similarity index 99% rename from src/Umbraco.Web.BackOffice/Filters/UmbracoAuthorizeFilter.cs rename to src/Umbraco.Web.Common/Filters/UmbracoAuthorizeFilter.cs index 6cf2eac5f0..66b1462ae9 100644 --- a/src/Umbraco.Web.BackOffice/Filters/UmbracoAuthorizeFilter.cs +++ b/src/Umbraco.Web.Common/Filters/UmbracoAuthorizeFilter.cs @@ -7,7 +7,7 @@ using Umbraco.Extensions; using Umbraco.Web.Security; using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; -namespace Umbraco.Web.BackOffice.Filters +namespace Umbraco.Web.Common.Filters { /// diff --git a/src/Umbraco.Web.Website/Controllers/RenderIndexActionSelectorAttribute.cs b/src/Umbraco.Web.Website/Controllers/RenderIndexActionSelectorAttribute.cs new file mode 100644 index 0000000000..f1ea65e983 --- /dev/null +++ b/src/Umbraco.Web.Website/Controllers/RenderIndexActionSelectorAttribute.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.ActionConstraints; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; + +namespace Umbraco.Web.Mvc +{ + /// + /// A custom ActionMethodSelector which will ensure that the RenderMvcController.Index(ContentModel model) action will be executed + /// if the + /// + internal class RenderIndexActionSelectorAttribute : ActionMethodSelectorAttribute + { + private static readonly ConcurrentDictionary> _controllerActionsCache = new ConcurrentDictionary>(); + + /// + /// Determines whether the action method selection is valid for the specified controller context. + /// + /// + /// true if the action method selection is valid for the specified controller context; otherwise, false. + /// + /// The route context. + /// Information about the action method. + public override bool IsValidForRequest(RouteContext routeContext, ActionDescriptor action) + { + if (action is ControllerActionDescriptor controllerAction) + { + var currType = controllerAction.ControllerTypeInfo.UnderlyingSystemType; + var baseType = controllerAction.ControllerTypeInfo.BaseType; + + //It's the same type, so this must be the Index action to use + if (currType == baseType) return true; + + var actions = _controllerActionsCache.GetOrAdd(currType, type => + { + var actionDescriptors = routeContext.HttpContext.RequestServices + .GetRequiredService().ActionDescriptors.Items + .Where(x=>x is ControllerActionDescriptor).Cast() + .Where(x => x.ControllerTypeInfo == controllerAction.ControllerTypeInfo); + + return actionDescriptors; + }); + + //If there are more than one Index action for this controller, then + // this base class one should not be matched + return actions.Count(x => x.ActionName == "Index") <= 1; + } + + return false; + + } + } +} diff --git a/src/Umbraco.Web.Website/Controllers/RenderMvcController.cs b/src/Umbraco.Web.Website/Controllers/RenderMvcController.cs new file mode 100644 index 0000000000..dab762aa3f --- /dev/null +++ b/src/Umbraco.Web.Website/Controllers/RenderMvcController.cs @@ -0,0 +1,94 @@ +using System; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ViewEngines; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Web.Common.Filters; +using Umbraco.Web.Models; +using Umbraco.Web.Routing; + +namespace Umbraco.Web.Mvc +{ + + /// + /// Represents the default front-end rendering controller. + /// + [PreRenderViewActionFilter] + [TypeFilter(typeof(ModelBindingExceptionFilter))] + public class RenderMvcController : UmbracoController, IRenderMvcController + { + private IPublishedRequest _publishedRequest; + private readonly ILogger _logger; + private readonly ICompositeViewEngine _compositeViewEngine; + + public RenderMvcController(ILogger logger, ICompositeViewEngine compositeViewEngine) + { + _logger = logger; + _compositeViewEngine = compositeViewEngine; + } + + + /// + /// Gets the current content item. + /// + protected IPublishedContent CurrentPage => PublishedRequest.PublishedContent; + + /// + /// Gets the current published content request. + /// + protected internal virtual IPublishedRequest PublishedRequest + { + get + { + if (_publishedRequest != null) + return _publishedRequest; + if (RouteData.DataTokens.ContainsKey(Core.Constants.Web.PublishedDocumentRequestDataToken) == false) + { + throw new InvalidOperationException("DataTokens must contain an 'umbraco-doc-request' key with a PublishedRequest object"); + } + _publishedRequest = (IPublishedRequest)RouteData.DataTokens[Core.Constants.Web.PublishedDocumentRequestDataToken]; + return _publishedRequest; + } + } + + /// + /// Ensures that a physical view file exists on disk. + /// + /// The view name. + protected bool EnsurePhsyicalViewExists(string template) + { + var result = _compositeViewEngine.FindView(ControllerContext, template, false); + if (result.View != null) return true; + + _logger.LogWarning("No physical template file was found for template {Template}", template); + return false; + } + + /// + /// Gets an action result based on the template name found in the route values and a model. + /// + /// The type of the model. + /// The model. + /// The action result. + /// If the template found in the route values doesn't physically exist, then an empty ContentResult will be returned. + protected IActionResult CurrentTemplate(T model) + { + var template = ControllerContext.RouteData.Values["action"].ToString(); + if (EnsurePhsyicalViewExists(template) == false) + throw new Exception("No physical template file was found for template " + template); + return View(template, model); + } + + /// + /// The default action to render the front-end view. + /// + /// + /// + [RenderIndexActionSelector] + public virtual IActionResult Index(ContentModel model) + { + return CurrentTemplate(model); + } + } +} diff --git a/src/Umbraco.Web.Website/Controllers/UmbracoAuthorizedController.cs b/src/Umbraco.Web.Website/Controllers/UmbracoAuthorizedController.cs new file mode 100644 index 0000000000..2b5d7a61da --- /dev/null +++ b/src/Umbraco.Web.Website/Controllers/UmbracoAuthorizedController.cs @@ -0,0 +1,18 @@ +using Umbraco.Web.Common.Filters; + +namespace Umbraco.Web.Mvc +{ + /// + /// Provides a base class for authorized Umbraco controllers. + /// + /// + /// This controller essentially just uses a global UmbracoAuthorizeAttribute, inheritors that require more granular control over the + /// authorization of each method can use this attribute instead of inheriting from this controller. + /// + [UmbracoAuthorize] + [DisableBrowserCache] + public abstract class UmbracoAuthorizedController : UmbracoController + { + + } +} diff --git a/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj b/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj index 683fd2cc6d..daba18d51b 100644 --- a/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj +++ b/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj @@ -23,4 +23,13 @@ + + + + <_Parameter1>Umbraco.Tests.UnitTests + + + <_Parameter1>Umbraco.Tests.Integration + + diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index f8848f64f0..1f7203270f 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -29,51 +29,36 @@ namespace Umbraco.Web.Editors /// [UmbracoRequireHttps] [DisableBrowserCache] - public class BackOfficeController : UmbracoController + public class BackOfficeController : Controller { - private readonly UmbracoFeatures _features; private BackOfficeOwinUserManager _userManager; private BackOfficeSignInManager _signInManager; - private readonly IUmbracoVersion _umbracoVersion; - private readonly ContentSettings _contentSettings; + private readonly IOptions _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; - private readonly RuntimeSettings _runtimeSettings; - private readonly SecuritySettings _securitySettings; - private readonly IIconService _iconService; + private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IUserService _userService; private readonly ILogger _logger; public BackOfficeController( - UmbracoFeatures features, IOptions globalSettings, - IUmbracoContextAccessor umbracoContextAccessor, - ServiceContext services, - AppCaches appCaches, - IProfilingLogger profilingLogger, ILoggerFactory loggerFactory, - IUmbracoVersion umbracoVersion, - IOptions contentSettings, IHostingEnvironment hostingEnvironment, - IOptions settings, - IOptions securitySettings, - IIconService iconService) - : base(globalSettings, umbracoContextAccessor, services, appCaches, profilingLogger, loggerFactory) - + IUmbracoContextAccessor umbracoContextAccessor, + IUserService userService + ) { - _features = features; - _umbracoVersion = umbracoVersion; - _contentSettings = contentSettings.Value; + _globalSettings = globalSettings; _hostingEnvironment = hostingEnvironment; - _runtimeSettings = settings.Value; - _securitySettings = securitySettings.Value; - _iconService = iconService; + _umbracoContextAccessor = umbracoContextAccessor; + _userService = userService; _logger = loggerFactory.CreateLogger(); } - protected BackOfficeSignInManager SignInManager => _signInManager ?? (_signInManager = OwinContext.GetBackOfficeSignInManager()); + protected BackOfficeSignInManager SignInManager => null; - protected BackOfficeOwinUserManager UserManager => _userManager ?? (_userManager = OwinContext.GetBackOfficeUserManager()); + protected BackOfficeOwinUserManager UserManager => null; - protected IAuthenticationManager AuthenticationManager => OwinContext.Authentication; + protected IAuthenticationManager AuthenticationManager => null; // TODO: for converting to netcore, some examples: @@ -148,7 +133,7 @@ namespace Umbraco.Web.Editors if (defaultResponse == null) throw new ArgumentNullException("defaultResponse"); if (externalSignInResponse == null) throw new ArgumentNullException("externalSignInResponse"); - ViewData.SetUmbracoPath(GlobalSettings.Value.GetUmbracoMvcArea(_hostingEnvironment)); + ViewData.SetUmbracoPath(_globalSettings.Value.GetUmbracoMvcArea(_hostingEnvironment)); //check if there is the TempData with the any token name specified, if so, assign to view bag and render the view if (ViewData.FromTempData(TempData, ViewDataExtensions.TokenExternalSignInError) || @@ -156,7 +141,7 @@ namespace Umbraco.Web.Editors return defaultResponse(); //First check if there's external login info, if there's not proceed as normal - var loginInfo = await OwinContext.Authentication.GetExternalLoginInfoAsync( + var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync( Constants.Security.BackOfficeExternalAuthenticationType); if (loginInfo == null || loginInfo.ExternalIdentity.IsAuthenticated == false) @@ -181,7 +166,7 @@ namespace Umbraco.Web.Editors // new users (auto-linked external accounts). This would never be used with public providers such as // Google, unless you for some reason wanted anybody to be able to access the backend if they have a Google account // .... not likely! - var authType = OwinContext.Authentication.GetExternalAuthenticationTypes().FirstOrDefault(x => x.AuthenticationType == loginInfo.Login.LoginProvider); + var authType = AuthenticationManager.GetExternalAuthenticationTypes().FirstOrDefault(x => x.AuthenticationType == loginInfo.Login.LoginProvider); if (authType == null) { _logger.LogWarning("Could not find external authentication provider registered: {LoginProvider}", loginInfo.Login.LoginProvider); @@ -239,7 +224,7 @@ namespace Umbraco.Web.Editors if (autoLinkOptions == null) return false; - if (autoLinkOptions.ShouldAutoLinkExternalAccount(UmbracoContext, loginInfo) == false) + if (autoLinkOptions.ShouldAutoLinkExternalAccount(_umbracoContextAccessor.UmbracoContext, loginInfo) == false) return true; //we are allowing auto-linking/creating of local accounts @@ -250,7 +235,7 @@ namespace Umbraco.Web.Editors else { //Now we need to perform the auto-link, so first we need to lookup/create a user with the email address - var foundByEmail = Services.UserService.GetByEmail(loginInfo.Email); + var foundByEmail = _userService.GetByEmail(loginInfo.Email); if (foundByEmail != null) { ViewData.SetExternalSignInError(new[] { "A user with this email address already exists locally. You will need to login locally to Umbraco and link this external provider: " + loginInfo.Login.LoginProvider }); @@ -260,12 +245,12 @@ namespace Umbraco.Web.Editors if (loginInfo.Email.IsNullOrWhiteSpace()) throw new InvalidOperationException("The Email value cannot be null"); if (loginInfo.ExternalIdentity.Name.IsNullOrWhiteSpace()) throw new InvalidOperationException("The Name value cannot be null"); - var groups = Services.UserService.GetUserGroupsByAlias(autoLinkOptions.GetDefaultUserGroups(UmbracoContext, loginInfo)); + var groups = _userService.GetUserGroupsByAlias(autoLinkOptions.GetDefaultUserGroups(_umbracoContextAccessor.UmbracoContext, loginInfo)); - var autoLinkUser = BackOfficeIdentityUser.CreateNew(GlobalSettings.Value, + var autoLinkUser = BackOfficeIdentityUser.CreateNew(_globalSettings.Value, loginInfo.Email, loginInfo.Email, - autoLinkOptions.GetDefaultCulture(UmbracoContext, loginInfo)); + autoLinkOptions.GetDefaultCulture(_umbracoContextAccessor.UmbracoContext, loginInfo)); autoLinkUser.Name = loginInfo.ExternalIdentity.Name; foreach (var userGroup in groups) { diff --git a/src/Umbraco.Web/Mvc/EnsurePartialViewMacroViewContextFilterAttribute.cs b/src/Umbraco.Web/Mvc/EnsurePartialViewMacroViewContextFilterAttribute.cs deleted file mode 100644 index f443abbb70..0000000000 --- a/src/Umbraco.Web/Mvc/EnsurePartialViewMacroViewContextFilterAttribute.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.IO; -using System.Web.Mvc; - -namespace Umbraco.Web.Mvc -{ - /// - /// This is a special filter which is required for the RTE to be able to render Partial View Macros that - /// contain forms when the RTE value is resolved outside of an MVC view being rendered - /// - /// - /// The entire way that we support partial view macros that contain forms isn't really great, these forms - /// need to be executed as ChildActions so that the ModelState,ViewData,TempData get merged into that action - /// so the form can show errors, viewdata, etc... - /// Under normal circumstances, macros will be rendered after a ViewContext is created but in some cases - /// developers will resolve the RTE value in the controller, in this case the Form won't be rendered correctly - /// with merged ModelState from the controller because the special DataToken hasn't been set yet (which is - /// normally done in the UmbracoViewPageOfModel when a real ViewContext is available. - /// So we need to detect if the currently rendering controller is IRenderController and if so we'll ensure that - /// this DataToken exists before the action executes in case the developer resolves an RTE value that contains - /// a partial view macro form. - /// - /// Migrated already to .Net Core - internal class EnsurePartialViewMacroViewContextFilterAttribute : ActionFilterAttribute - { - /// - /// Ensures the custom ViewContext datatoken is set before the RenderController action is invoked, - /// this ensures that any calls to GetPropertyValue with regards to RTE or Grid editors can still - /// render any PartialViewMacro with a form and maintain ModelState - /// - /// - public override void OnActionExecuting(ActionExecutingContext filterContext) - { - //ignore anything that is not IRenderController - if ((filterContext.Controller is IRenderController) == false && filterContext.IsChildAction == false) - return; - - SetViewContext(filterContext); - } - - /// - /// Ensures that the custom ViewContext datatoken is set after the RenderController action is invoked, - /// this ensures that any custom ModelState that may have been added in the RenderController itself is - /// passed onwards in case it is required when rendering a PartialViewMacro with a form - /// - /// The filter context. - public override void OnResultExecuting(ResultExecutingContext filterContext) - { - //ignore anything that is not IRenderController - if ((filterContext.Controller is IRenderController) == false && filterContext.IsChildAction == false) - return; - - SetViewContext(filterContext); - } - - private void SetViewContext(ControllerContext controllerContext) - { - var viewCtx = new ViewContext( - controllerContext, - new DummyView(), - controllerContext.Controller.ViewData, controllerContext.Controller.TempData, - new StringWriter()); - - //set the special data token - controllerContext.RequestContext.RouteData.DataTokens[Constants.DataTokenCurrentViewContext] = viewCtx; - } - - private class DummyView : IView - { - public void Render(ViewContext viewContext, TextWriter writer) - { - } - } - } -} diff --git a/src/Umbraco.Web/Mvc/IRenderMvcController.cs b/src/Umbraco.Web/Mvc/IRenderMvcController.cs index 492291d7c0..542e46ac2c 100644 --- a/src/Umbraco.Web/Mvc/IRenderMvcController.cs +++ b/src/Umbraco.Web/Mvc/IRenderMvcController.cs @@ -1,19 +1,8 @@ -using System.Web.Mvc; -using Umbraco.Core.Composing; -using Umbraco.Web.Models; - -namespace Umbraco.Web.Mvc +namespace Umbraco.Web.Mvc { - /// - /// The interface that must be implemented for a controller to be designated to execute for route hijacking - /// - public interface IRenderMvcController : IRenderController, IDiscoverable + //Migrated to .NET Core + public interface IRenderMvcController : IRenderController { - /// - /// The default action to render the front-end view - /// - /// - /// - ActionResult Index(ContentModel model); + } } diff --git a/src/Umbraco.Web/Mvc/RenderActionInvoker.cs b/src/Umbraco.Web/Mvc/RenderActionInvoker.cs index c86d2f77c3..47e77bb4f4 100644 --- a/src/Umbraco.Web/Mvc/RenderActionInvoker.cs +++ b/src/Umbraco.Web/Mvc/RenderActionInvoker.cs @@ -13,8 +13,6 @@ namespace Umbraco.Web.Mvc /// public class RenderActionInvoker : AsyncControllerActionInvoker { - - /// /// Ensures that if an action for the Template name is not explicitly defined by a user, that the 'Index' action will execute /// diff --git a/src/Umbraco.Web/Mvc/RenderIndexActionSelectorAttribute.cs b/src/Umbraco.Web/Mvc/RenderIndexActionSelectorAttribute.cs deleted file mode 100644 index 99aa88b3e2..0000000000 --- a/src/Umbraco.Web/Mvc/RenderIndexActionSelectorAttribute.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Linq; -using System.Reflection; -using System.Web.Mvc; - -namespace Umbraco.Web.Mvc -{ - /// - /// A custom ActionMethodSelector which will ensure that the RenderMvcController.Index(ContentModel model) action will be executed - /// if the - /// - internal class RenderIndexActionSelectorAttribute : ActionMethodSelectorAttribute - { - private static readonly ConcurrentDictionary ControllerDescCache = new ConcurrentDictionary(); - - /// - /// Determines whether the action method selection is valid for the specified controller context. - /// - /// - /// true if the action method selection is valid for the specified controller context; otherwise, false. - /// - /// The controller context.Information about the action method. - public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) - { - var currType = methodInfo.ReflectedType; - var baseType = methodInfo.DeclaringType; - - //It's the same type, so this must be the Index action to use - if (currType == baseType) return true; - - if (currType == null) return false; - - var controllerDesc = ControllerDescCache.GetOrAdd(currType, type => new ReflectedControllerDescriptor(currType)); - var actions = controllerDesc.GetCanonicalActions(); - - //If there are more than one Index action for this controller, then - // this base class one should not be matched - return actions.Count(x => x.ActionName == "Index") <= 1; - } - } -} diff --git a/src/Umbraco.Web/Mvc/RenderMvcController.cs b/src/Umbraco.Web/Mvc/RenderMvcController.cs index 42fef69f0f..1a4a32eadf 100644 --- a/src/Umbraco.Web/Mvc/RenderMvcController.cs +++ b/src/Umbraco.Web/Mvc/RenderMvcController.cs @@ -1,106 +1,11 @@ -using System; using System.Web.Mvc; -using Microsoft.Extensions.Options; -using Microsoft.Extensions.Logging; -using Umbraco.Core.Cache; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Logging; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.Services; -using Umbraco.Web.Models; -using Umbraco.Web.Routing; namespace Umbraco.Web.Mvc { - - /// - /// Represents the default front-end rendering controller. - /// - [PreRenderViewActionFilter] - [ModelBindingExceptionFilter] - public class RenderMvcController : UmbracoController, IRenderMvcController + //Migrated to .NET Core + public class RenderMvcController : Controller, IRenderMvcController { - private IPublishedRequest _publishedRequest; - private readonly ILogger _logger; - public RenderMvcController() - { - ActionInvoker = new RenderActionInvoker(); - } - public RenderMvcController(IOptions globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, ILoggerFactory loggerFactory) - : base(globalSettings, umbracoContextAccessor, services, appCaches, profilingLogger, loggerFactory) - { - ActionInvoker = new RenderActionInvoker(); - _logger = loggerFactory.CreateLogger(); - } - - /// - /// Gets the Umbraco context. - /// - public override IUmbracoContext UmbracoContext => PublishedRequest.UmbracoContext; //TODO: Why? - - /// - /// Gets the current content item. - /// - protected IPublishedContent CurrentPage => PublishedRequest.PublishedContent; - - /// - /// Gets the current published content request. - /// - protected internal virtual IPublishedRequest PublishedRequest - { - get - { - if (_publishedRequest != null) - return _publishedRequest; - if (RouteData.DataTokens.ContainsKey(Core.Constants.Web.PublishedDocumentRequestDataToken) == false) - { - throw new InvalidOperationException("DataTokens must contain an 'umbraco-doc-request' key with a PublishedRequest object"); - } - _publishedRequest = (IPublishedRequest)RouteData.DataTokens[Core.Constants.Web.PublishedDocumentRequestDataToken]; - return _publishedRequest; - } - } - - /// - /// Ensures that a physical view file exists on disk. - /// - /// The view name. - protected bool EnsurePhsyicalViewExists(string template) - { - var result = ViewEngines.Engines.FindView(ControllerContext, template, null); - if (result.View != null) return true; - - _logger.LogWarning("No physical template file was found for template {Template}", template); - return false; - } - - /// - /// Gets an action result based on the template name found in the route values and a model. - /// - /// The type of the model. - /// The model. - /// The action result. - /// If the template found in the route values doesn't physically exist, then an empty ContentResult will be returned. - protected ActionResult CurrentTemplate(T model) - { - var template = ControllerContext.RouteData.Values["action"].ToString(); - if (EnsurePhsyicalViewExists(template) == false) - throw new Exception("No physical template file was found for template " + template); - return View(template, model); - } - - /// - /// The default action to render the front-end view. - /// - /// - /// - [RenderIndexActionSelector] - public virtual ActionResult Index(ContentModel model) - { - return CurrentTemplate(model); - } } } diff --git a/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs b/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs deleted file mode 100644 index 520a0ef738..0000000000 --- a/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Microsoft.Extensions.Options; -using Microsoft.Extensions.Logging; -using Umbraco.Core.Cache; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence; -using Umbraco.Core.Services; - -namespace Umbraco.Web.Mvc -{ - /// - /// Provides a base class for authorized Umbraco controllers. - /// - /// - /// This controller essentially just uses a global UmbracoAuthorizeAttribute, inheritors that require more granular control over the - /// authorization of each method can use this attribute instead of inheriting from this controller. - /// - [UmbracoAuthorize] - [DisableBrowserCache] - public abstract class UmbracoAuthorizedController : UmbracoController - { - protected UmbracoAuthorizedController() - { - } - - protected UmbracoAuthorizedController(IOptions globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, ILoggerFactory loggerFactory) - : base(globalSettings, umbracoContextAccessor, services, appCaches, profilingLogger, loggerFactory) - { - } - } -} diff --git a/src/Umbraco.Web/Mvc/UmbracoController.cs b/src/Umbraco.Web/Mvc/UmbracoController.cs deleted file mode 100644 index be46c30dd9..0000000000 --- a/src/Umbraco.Web/Mvc/UmbracoController.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System; -using System.Web; -using System.Web.Mvc; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Microsoft.Owin; -using Umbraco.Core.Cache; -using Umbraco.Web.Composing; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core; -using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Services; -using Umbraco.Web.Security; - -namespace Umbraco.Web.Mvc -{ - /// - /// Provides a base class for Umbraco controllers. - /// - public abstract class UmbracoController : Controller - { - // for debugging purposes - internal Guid InstanceId { get; } = Guid.NewGuid(); - - /// - /// Gets or sets the Umbraco context. - /// - public IOptions GlobalSettings { get; } - - /// - /// Gets the Umbraco context. - /// - public virtual IUmbracoContext UmbracoContext => UmbracoContextAccessor.UmbracoContext; - - /// - /// Gets or sets the Umbraco context accessor. - /// - public IUmbracoContextAccessor UmbracoContextAccessor { get; set; } - - /// - /// Gets or sets the services context. - /// - public ServiceContext Services { get; } - - /// - /// Gets or sets the application cache. - /// - public AppCaches AppCaches { get; } - - - /// - /// Gets or sets the profiling logger. - /// - public IProfilingLogger ProfilingLogger { get; set; } - - /// - /// Gets the LoggerFactory - /// - public ILoggerFactory LoggerFactory { get; } - - protected IOwinContext OwinContext => Request.GetOwinContext(); - - /// - /// Gets the Umbraco helper. - /// - public UmbracoHelper Umbraco { get; } - - /// - /// Gets the web security helper. - /// - public virtual IBackofficeSecurity Security => UmbracoContext.Security; - - protected UmbracoController() - : this( - Current.Factory.GetInstance>(), - Current.Factory.GetInstance(), - Current.Factory.GetInstance(), - Current.Factory.GetInstance(), - Current.Factory.GetInstance(), - Current.Factory.GetInstance() - ) - { - } - - protected UmbracoController(IOptions globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, ILoggerFactory loggerFactory) - { - GlobalSettings = globalSettings; - UmbracoContextAccessor = umbracoContextAccessor; - Services = services; - AppCaches = appCaches; - ProfilingLogger = profilingLogger; - LoggerFactory = loggerFactory; - } - } -} diff --git a/src/Umbraco.Web/Runtime/WebInitialComponent.cs b/src/Umbraco.Web/Runtime/WebInitialComponent.cs index 9108dd820e..a5c7db12c9 100644 --- a/src/Umbraco.Web/Runtime/WebInitialComponent.cs +++ b/src/Umbraco.Web/Runtime/WebInitialComponent.cs @@ -66,7 +66,7 @@ namespace Umbraco.Web.Runtime private static void ConfigureGlobalFilters() { - GlobalFilters.Filters.Add(new EnsurePartialViewMacroViewContextFilterAttribute()); + //GlobalFilters.Filters.Add(new EnsurePartialViewMacroViewContextFilterAttribute()); } // internal for tests diff --git a/src/Umbraco.Web/Runtime/WebInitialComposer.cs b/src/Umbraco.Web/Runtime/WebInitialComposer.cs index 90706f346f..591a3698e7 100644 --- a/src/Umbraco.Web/Runtime/WebInitialComposer.cs +++ b/src/Umbraco.Web/Runtime/WebInitialComposer.cs @@ -1,4 +1,5 @@ -using System.Web.Security; +using System.Web.Mvc; +using System.Web.Security; using Microsoft.AspNet.SignalR; using Umbraco.Core; using Umbraco.Core.Composing; @@ -58,7 +59,7 @@ namespace Umbraco.Web.Runtime composition // TODO: This will depend on if we use ServiceBasedControllerActivator - see notes in Startup.cs .ComposeUmbracoControllers(GetType().Assembly) - .SetDefaultRenderMvcController(); // default controller for template views + .SetDefaultRenderMvcController(); // default controller for template views //we need to eagerly scan controller types since they will need to be routed composition.WithCollectionBuilder() diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 5f6ce7fc84..2395fa254c 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -155,6 +155,9 @@ + + + @@ -240,10 +243,7 @@ - - - @@ -309,7 +309,6 @@ - @@ -327,8 +326,6 @@ - - @@ -362,7 +359,6 @@ -