diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index 5e685c9b3d7..9ca714922b7 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -2,15 +2,29 @@ name: Compile on: workflow_dispatch: + pull_request: + push: + branches: + - dev + - 1.10.x jobs: compile: name: Compile defaults: run: - shell: cmd + shell: pwsh runs-on: windows-latest steps: - - name: Test - run: echo Test + - name: Clone repository + uses: actions/checkout@v3.1.0 + + - name: Restore NuGet packages + run: nuget restore src/Orchard.sln + + - name: Add msbuild to PATH + uses: microsoft/setup-msbuild@v1.3.1 + + - name: Compile + run: msbuild Orchard.proj /m /t:Compile /p:MvcBuildViews=true /p:TreatWarningsAsErrors=true -WarnAsError diff --git a/Orchard.proj b/Orchard.proj index 28c85bc54a5..590bfb4d87d 100644 --- a/Orchard.proj +++ b/Orchard.proj @@ -165,7 +165,7 @@ - + diff --git a/src/Libraries/NHibernate/NHibernate.Linq/NHibernate.Linq.csproj b/src/Libraries/NHibernate/NHibernate.Linq/NHibernate.Linq.csproj index 309880b83b1..46467801f78 100644 --- a/src/Libraries/NHibernate/NHibernate.Linq/NHibernate.Linq.csproj +++ b/src/Libraries/NHibernate/NHibernate.Linq/NHibernate.Linq.csproj @@ -123,9 +123,6 @@ - - NH.Linq.snk - diff --git a/src/Orchard.Core.Tests/Common/Providers/CommonPartProviderTests.cs b/src/Orchard.Core.Tests/Common/Providers/CommonPartProviderTests.cs index c0008ad5936..06c1a21acdd 100644 --- a/src/Orchard.Core.Tests/Common/Providers/CommonPartProviderTests.cs +++ b/src/Orchard.Core.Tests/Common/Providers/CommonPartProviderTests.cs @@ -177,7 +177,7 @@ public void PublishingShouldFailIfOwnerIsUnknown() { contentManager.UpdateEditor(item.ContentItem, updateModel.Object); } - class UpdatModelStub : IUpdateModel { + class UpdateModelStub : IUpdateModel { ModelStateDictionary _modelState = new ModelStateDictionary(); @@ -215,11 +215,11 @@ public void PublishingShouldNotThrowExceptionIfOwnerIsNull() { var user = contentManager.New("User"); _authn.Setup(x => x.GetAuthenticatedUser()).Returns(user); - _authz.Setup(x => x.TryCheckAccess(StandardPermissions.SiteOwner, user, item)).Returns(true); + _authz.Setup(x => x.TryCheckAccess(OwnerEditorPermissions.MayEditContentOwner, user, item)).Returns(true); item.Owner = user; - var updater = new UpdatModelStub() { Owner = null }; + var updater = new UpdateModelStub() { Owner = null }; contentManager.UpdateEditor(item.ContentItem, updater); } @@ -232,11 +232,11 @@ public void PublishingShouldFailIfOwnerIsEmpty() { var user = contentManager.New("User"); _authn.Setup(x => x.GetAuthenticatedUser()).Returns(user); - _authz.Setup(x => x.TryCheckAccess(StandardPermissions.SiteOwner, user, item)).Returns(true); + _authz.Setup(x => x.TryCheckAccess(OwnerEditorPermissions.MayEditContentOwner, user, item)).Returns(true); item.Owner = user; - var updater = new UpdatModelStub() { Owner = "" }; + var updater = new UpdateModelStub() { Owner = "" }; _container.Resolve().Discover = b => b.Describe("Parts_Common_Owner_Edit").From(TestFeature()) @@ -255,11 +255,11 @@ public void PublishingShouldNotFailIfOwnerIsEmptyAndShapeIsHidden() { var user = contentManager.New("User"); _authn.Setup(x => x.GetAuthenticatedUser()).Returns(user); - _authz.Setup(x => x.TryCheckAccess(StandardPermissions.SiteOwner, user, item)).Returns(true); + _authz.Setup(x => x.TryCheckAccess(OwnerEditorPermissions.MayEditContentOwner, user, item)).Returns(true); item.Owner = user; - var updater = new UpdatModelStub() { Owner = "" }; + var updater = new UpdateModelStub() { Owner = "" }; _container.Resolve().Discover = b => b.Describe("Parts_Common_Owner_Edit").From(TestFeature()) @@ -384,7 +384,7 @@ public void EditingShouldSetModifiedUtc() { _clock.Advance(TimeSpan.FromMinutes(1)); var editUtc = _clock.UtcNow; - var updater = new UpdatModelStub() { Owner = "" }; + var updater = new UpdateModelStub() { Owner = "" }; contentManager.UpdateEditor(item.ContentItem, updater); Assert.That(item.CreatedUtc, Is.EqualTo(createUtc)); diff --git a/src/Orchard.Profile/App.config b/src/Orchard.Profile/App.config index f40de4fce56..ea3c48e0510 100644 --- a/src/Orchard.Profile/App.config +++ b/src/Orchard.Profile/App.config @@ -3,9 +3,7 @@
- - - + diff --git a/src/Orchard.Specs/Bindings/Settings.cs b/src/Orchard.Specs/Bindings/Settings.cs index 607c01ab060..4bd67b7508b 100644 --- a/src/Orchard.Specs/Bindings/Settings.cs +++ b/src/Orchard.Specs/Bindings/Settings.cs @@ -1,15 +1,7 @@ -using System; -using NUnit.Framework; -using Orchard.ContentManagement; -using Orchard.ContentManagement.Aspects; -using Orchard.Core.Contents; -using Orchard.Data; -using Orchard.Security; -using Orchard.Security.Permissions; +using System.Linq; +using Orchard.Localization.Services; using Orchard.Specs.Hosting.Orchard.Web; using TechTalk.SpecFlow; -using Orchard.Localization.Services; -using System.Linq; namespace Orchard.Specs.Bindings { [Binding] @@ -20,7 +12,7 @@ public void DefineDefaultCulture(string cultureName) { var webApp = Binding(); webApp.Host.Execute(() => { - using ( var environment = MvcApplication.CreateStandaloneEnvironment("Default") ) { + using (var environment = MvcApplication.CreateStandaloneEnvironment("Default")) { var orchardServices = environment.Resolve(); var cultureManager = environment.Resolve(); @@ -30,6 +22,11 @@ public void DefineDefaultCulture(string cultureName) { } orchardServices.WorkContext.CurrentSite.SiteCulture = cultureName; + + // Restarting the shell to reset the cache, because the cache entry storing the list of available + // cultures isn't invalidated by the signal in DefaultCultureManager.ListCultures when running + // inside the test webhost. + MvcApplication.RestartTenant("Default"); } }); } diff --git a/src/Orchard.Specs/Bindings/WebAppHosting.cs b/src/Orchard.Specs/Bindings/WebAppHosting.cs index 08ea4c83028..18e041f1579 100644 --- a/src/Orchard.Specs/Bindings/WebAppHosting.cs +++ b/src/Orchard.Specs/Bindings/WebAppHosting.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using System.Text.RegularExpressions; +using System.Threading; using System.Web; using Castle.Core.Logging; using HtmlAgilityPack; @@ -368,6 +369,11 @@ public void WhenIAmRedirected() { } } + [When(@"I wait ""(.*)""")] + public void WhenIWait(int waitMilliseconds) { + Thread.Sleep(waitMilliseconds); + } + [Then(@"the status should be (.*) ""(.*)""")] public void ThenTheStatusShouldBe(int statusCode, string statusDescription) { Assert.That(Details.StatusCode, Is.EqualTo(statusCode)); diff --git a/src/Orchard.Specs/Blogs.feature b/src/Orchard.Specs/Blogs.feature index 69dc68bc944..dcd3c8bb7f7 100644 --- a/src/Orchard.Specs/Blogs.feature +++ b/src/Orchard.Specs/Blogs.feature @@ -171,6 +171,7 @@ Scenario: I can create browse blog posts on several pages And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 1 | @@ -179,6 +180,7 @@ Scenario: I can create browse blog posts on several pages And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 2 | @@ -187,6 +189,7 @@ Scenario: I can create browse blog posts on several pages And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 3 | @@ -195,6 +198,7 @@ Scenario: I can create browse blog posts on several pages And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 4 | @@ -203,6 +207,7 @@ Scenario: I can create browse blog posts on several pages And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 5 | @@ -211,6 +216,7 @@ Scenario: I can create browse blog posts on several pages And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 6 | @@ -219,6 +225,7 @@ Scenario: I can create browse blog posts on several pages And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 7 | @@ -227,6 +234,7 @@ Scenario: I can create browse blog posts on several pages And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 8 | @@ -235,6 +243,7 @@ Scenario: I can create browse blog posts on several pages And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 9 | @@ -243,6 +252,7 @@ Scenario: I can create browse blog posts on several pages And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 10 | @@ -251,6 +261,7 @@ Scenario: I can create browse blog posts on several pages And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 11 | @@ -259,6 +270,7 @@ Scenario: I can create browse blog posts on several pages And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 12 | @@ -269,12 +281,12 @@ Scenario: I can create browse blog posts on several pages Then I should see "]*>.*?My Blog.*?" And I should see "]*>.*?My Post 12.*?" And I should see "]*>.*?My Post 11.*?" - And I should not see "]*>.*?My Post 10.*?" + And I should not see "My Post 2" When I go to "my-blog?page=2" Then I should see "]*>.*?My Blog.*?" And I should see "]*>.*?My Post 1.*?" And I should see "]*>.*?My Post 2.*?" - And I should not see "]*>.*?My Post 3.*?" + And I should not see "My Post 3" Scenario: I can create a new blog with a percent sign in the title and it gets stripped out of the slug Given I have installed Orchard diff --git a/src/Orchard.Specs/Blogs.feature.cs b/src/Orchard.Specs/Blogs.feature.cs index fdcfe5eeee9..7721afb0aa7 100644 --- a/src/Orchard.Specs/Blogs.feature.cs +++ b/src/Orchard.Specs/Blogs.feature.cs @@ -525,6 +525,8 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 173 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 174 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table15 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -532,18 +534,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table15.AddRow(new string[] { "Title.Title", "My Post 1"}); -#line 174 +#line 175 testRunner.And("I fill in", ((string)(null)), table15, "And "); -#line 177 - testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 178 - testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 179 - testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 180 - testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 181 + testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 182 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 183 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table16 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -551,18 +555,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table16.AddRow(new string[] { "Title.Title", "My Post 2"}); -#line 182 +#line 184 testRunner.And("I fill in", ((string)(null)), table16, "And "); -#line 185 +#line 187 testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 186 +#line 188 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 187 +#line 189 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 188 +#line 190 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 189 +#line 191 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 192 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table17 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -570,18 +576,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table17.AddRow(new string[] { "Title.Title", "My Post 3"}); -#line 190 - testRunner.And("I fill in", ((string)(null)), table17, "And "); #line 193 + testRunner.And("I fill in", ((string)(null)), table17, "And "); +#line 196 testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 194 +#line 197 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 195 +#line 198 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 196 +#line 199 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 197 +#line 200 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 201 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table18 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -589,18 +597,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table18.AddRow(new string[] { "Title.Title", "My Post 4"}); -#line 198 +#line 202 testRunner.And("I fill in", ((string)(null)), table18, "And "); -#line 201 +#line 205 testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 202 +#line 206 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 203 +#line 207 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 204 +#line 208 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 205 +#line 209 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 210 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table19 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -608,18 +618,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table19.AddRow(new string[] { "Title.Title", "My Post 5"}); -#line 206 +#line 211 testRunner.And("I fill in", ((string)(null)), table19, "And "); -#line 209 +#line 214 testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 210 +#line 215 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 211 +#line 216 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 212 +#line 217 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 213 +#line 218 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 219 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table20 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -627,18 +639,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table20.AddRow(new string[] { "Title.Title", "My Post 6"}); -#line 214 +#line 220 testRunner.And("I fill in", ((string)(null)), table20, "And "); -#line 217 +#line 223 testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 218 +#line 224 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 219 +#line 225 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 220 +#line 226 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 221 +#line 227 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 228 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table21 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -646,18 +660,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table21.AddRow(new string[] { "Title.Title", "My Post 7"}); -#line 222 +#line 229 testRunner.And("I fill in", ((string)(null)), table21, "And "); -#line 225 +#line 232 testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 226 +#line 233 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 227 +#line 234 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 228 +#line 235 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 229 +#line 236 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 237 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table22 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -665,18 +681,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table22.AddRow(new string[] { "Title.Title", "My Post 8"}); -#line 230 +#line 238 testRunner.And("I fill in", ((string)(null)), table22, "And "); -#line 233 +#line 241 testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 234 +#line 242 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 235 +#line 243 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 236 +#line 244 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 237 +#line 245 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 246 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table23 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -684,18 +702,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table23.AddRow(new string[] { "Title.Title", "My Post 9"}); -#line 238 +#line 247 testRunner.And("I fill in", ((string)(null)), table23, "And "); -#line 241 +#line 250 testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 242 +#line 251 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 243 +#line 252 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 244 +#line 253 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 245 +#line 254 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 255 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table24 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -703,18 +723,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table24.AddRow(new string[] { "Title.Title", "My Post 10"}); -#line 246 +#line 256 testRunner.And("I fill in", ((string)(null)), table24, "And "); -#line 249 +#line 259 testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 250 +#line 260 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 251 +#line 261 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 252 +#line 262 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 253 +#line 263 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 264 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table25 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -722,18 +744,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table25.AddRow(new string[] { "Title.Title", "My Post 11"}); -#line 254 +#line 265 testRunner.And("I fill in", ((string)(null)), table25, "And "); -#line 257 +#line 268 testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 258 +#line 269 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 259 +#line 270 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 260 +#line 271 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 261 +#line 272 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 273 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table26 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -741,34 +765,34 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table26.AddRow(new string[] { "Title.Title", "My Post 12"}); -#line 262 +#line 274 testRunner.And("I fill in", ((string)(null)), table26, "And "); -#line 265 +#line 277 testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 266 +#line 278 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 267 +#line 279 testRunner.Then("I should see \"Your Blog Post has been created.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 268 +#line 280 testRunner.When("I go to \"my-blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 269 +#line 281 testRunner.Then("I should see \"]*>.*?My Blog.*?\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 270 +#line 282 testRunner.And("I should see \"]*>.*?My Post 12.*?\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 271 +#line 283 testRunner.And("I should see \"]*>.*?My Post 11.*?\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 272 - testRunner.And("I should not see \"]*>.*?My Post 10.*?\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 273 +#line 284 + testRunner.And("I should not see \"My Post 2\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 285 testRunner.When("I go to \"my-blog?page=2\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 274 +#line 286 testRunner.Then("I should see \"]*>.*?My Blog.*?\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 275 +#line 287 testRunner.And("I should see \"]*>.*?My Post 1.*?\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 276 +#line 288 testRunner.And("I should see \"]*>.*?My Post 2.*?\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 277 - testRunner.And("I should not see \"]*>.*?My Post 3.*?\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 289 + testRunner.And("I should not see \"My Post 3\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden this.ScenarioCleanup(); } @@ -780,11 +804,11 @@ public virtual void ICanCreateANewBlogWithAPercentSignInTheTitleAndItGetsStrippe { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("I can create a new blog with a percent sign in the title and it gets stripped out" + " of the slug", ((string[])(null))); -#line 279 +#line 291 this.ScenarioSetup(scenarioInfo); -#line 280 +#line 292 testRunner.Given("I have installed Orchard", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); -#line 281 +#line 293 testRunner.When("I go to \"admin/blogs/create\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden TechTalk.SpecFlow.Table table27 = new TechTalk.SpecFlow.Table(new string[] { @@ -793,15 +817,15 @@ public virtual void ICanCreateANewBlogWithAPercentSignInTheTitleAndItGetsStrippe table27.AddRow(new string[] { "Title.Title", "My Blog"}); -#line 282 +#line 294 testRunner.And("I fill in", ((string)(null)), table27, "And "); -#line 285 +#line 297 testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 286 +#line 298 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 287 +#line 299 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 288 +#line 300 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table28 = new TechTalk.SpecFlow.Table(new string[] { @@ -813,15 +837,15 @@ public virtual void ICanCreateANewBlogWithAPercentSignInTheTitleAndItGetsStrippe table28.AddRow(new string[] { "Body.Text", "Hi there."}); -#line 289 +#line 301 testRunner.And("I fill in", ((string)(null)), table28, "And "); -#line 293 +#line 305 testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 294 +#line 306 testRunner.And("I go to \"my-blog/my-post-with-a-sign\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 295 +#line 307 testRunner.Then("I should see \"]*>.*?My Post with a % Sign.*?\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 296 +#line 308 testRunner.And("I should see \"Hi there.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden this.ScenarioCleanup(); diff --git a/src/Orchard.Specs/DateTime.feature b/src/Orchard.Specs/DateTime.feature index 208e0ff67e4..17e76180f16 100644 --- a/src/Orchard.Specs/DateTime.feature +++ b/src/Orchard.Specs/DateTime.feature @@ -163,7 +163,7 @@ Scenario: Creating and using date time fields in another culture And I go to "Admin/ContentTypes/" Then I should see "Event" - # Adding a Date field + # Adding a Date field and changing its settings When I go to "Admin/ContentTypes/Edit/Event" And I follow "Add Field" And I fill in @@ -174,15 +174,15 @@ Scenario: Creating and using date time fields in another culture And I hit "Save" And I am redirected Then I should see "The \"Date of the event\" field has been added." - - # Date & Time are inputted based on current culture - When I have "fr-FR" as the default culture - And I go to "Admin/ContentTypes/Edit/Event" + When I go to "Admin/ContentTypes/Edit/Event" And I fill in | name | value | | Fields[EventDate].DateTimeFieldSettings.Display | DateAndTime | | Fields[EventDate].DateTimeFieldSettings.Required | true | And I hit "Save" + + # Date & Time are validated based on current culture + When I have "fr-FR" as the default culture When I go to "Admin/Contents/Create/Event" And I fill in | name | value | diff --git a/src/Orchard.Specs/DateTime.feature.cs b/src/Orchard.Specs/DateTime.feature.cs index 6ad81081e7e..2d8c64dacfd 100644 --- a/src/Orchard.Specs/DateTime.feature.cs +++ b/src/Orchard.Specs/DateTime.feature.cs @@ -426,10 +426,8 @@ public virtual void CreatingAndUsingDateTimeFieldsInAnotherCulture() testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 176 testRunner.Then("I should see \"The \\\"Date of the event\\\" field has been added.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 179 - testRunner.When("I have \"fr-FR\" as the default culture", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 180 - testRunner.And("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 177 + testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden TechTalk.SpecFlow.Table table16 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -440,10 +438,12 @@ public virtual void CreatingAndUsingDateTimeFieldsInAnotherCulture() table16.AddRow(new string[] { "Fields[EventDate].DateTimeFieldSettings.Required", "true"}); -#line 181 +#line 178 testRunner.And("I fill in", ((string)(null)), table16, "And "); -#line 185 +#line 182 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 185 + testRunner.When("I have \"fr-FR\" as the default culture", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line 186 testRunner.When("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden diff --git a/src/Orchard.Specs/Hosting/Orchard.Web/Global.asax.cs b/src/Orchard.Specs/Hosting/Orchard.Web/Global.asax.cs index f98e7cf48fd..b74924eedc7 100644 --- a/src/Orchard.Specs/Hosting/Orchard.Web/Global.asax.cs +++ b/src/Orchard.Specs/Hosting/Orchard.Web/Global.asax.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Web; +using System.Web.Helpers; using System.Web.Mvc; using System.Web.Routing; using Autofac; @@ -16,6 +17,7 @@ public static void RegisterRoutes(RouteCollection routes) { } protected void Application_Start() { + AntiForgeryConfig.SuppressXFrameOptionsHeader = true; RegisterRoutes(RouteTable.Routes); _container = OrchardStarter.CreateHostContainer(MvcSingletons); _host = _container.Resolve(); @@ -29,6 +31,7 @@ protected void Application_Start() { protected void Application_BeginRequest() { Context.Items["originalHttpContext"] = Context; + HttpContext.Current.Response.AddHeader("X-Frame-Options", "SAMEORIGIN"); _host.BeginRequest(); } @@ -66,7 +69,7 @@ public static IWorkContextScope CreateStandaloneEnvironment(string name) { State = TenantState.Uninitialized }; } - + return _host.CreateStandaloneEnvironment(settings); } } diff --git a/src/Orchard.Specs/Hosting/Orchard.Web/Web.config b/src/Orchard.Specs/Hosting/Orchard.Web/Web.config index 2f2df5a9d2d..79431085e04 100644 --- a/src/Orchard.Specs/Hosting/Orchard.Web/Web.config +++ b/src/Orchard.Specs/Hosting/Orchard.Web/Web.config @@ -100,7 +100,6 @@ - @@ -155,34 +154,22 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Specs/Media.feature b/src/Orchard.Specs/Media.feature index 4f4b6dfb7b8..2696dbfba88 100644 --- a/src/Orchard.Specs/Media.feature +++ b/src/Orchard.Specs/Media.feature @@ -1,31 +1,13 @@ Feature: Media management In order to reference images and such from content As an author - I want to upload and manage files in a media folder + I want to access the Media Library Scenario: Media admin is available Given I have installed Orchard - And I have installed "Orchard.Media" + And I have installed "Orchard.MediaLibrary" - # Accessing the media page - When I go to "admin/media" - Then I should see "Media" - And the status should be 200 "OK" - - # Creating a folder - When I go to "admin/media/create" - And I fill in - | name | value | - | Name | Hello World | - And I hit "Save" - And I am redirected - Then I should see "Media" - And I should see "Hello World" - And the status should be 200 "OK" - - # Editing a media with limited rights - When I go to "admin/media/edit?name=..\..\bin&mediaPath=..\..\bin" - And I am redirected - Then I should see "Media" - And I should see "Editing failed: Invalid path" - And the status should be 200 "OK" + # Accessing the Media Library page + When I go to "Admin/Orchard.MediaLibrary" + Then I should see "Media Library" + And the status should be 200 "OK" diff --git a/src/Orchard.Specs/Media.feature.cs b/src/Orchard.Specs/Media.feature.cs index 55efb6a0a81..798b7a9b2d3 100644 --- a/src/Orchard.Specs/Media.feature.cs +++ b/src/Orchard.Specs/Media.feature.cs @@ -33,7 +33,7 @@ public virtual void FeatureSetup() { testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner(); TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "Media management", " In order to reference images and such from content\r\n As an author\r\n I want to" + - " upload and manage files in a media folder", ProgrammingLanguage.CSharp, ((string[])(null))); + " access the Media Library", ProgrammingLanguage.CSharp, ((string[])(null))); testRunner.OnFeatureStart(featureInfo); } @@ -75,44 +75,13 @@ public virtual void MediaAdminIsAvailable() #line 7 testRunner.Given("I have installed Orchard", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); #line 8 - testRunner.And("I have installed \"Orchard.Media\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I have installed \"Orchard.MediaLibrary\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 11 - testRunner.When("I go to \"admin/media\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); + testRunner.When("I go to \"Admin/Orchard.MediaLibrary\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line 12 - testRunner.Then("I should see \"Media\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); + testRunner.Then("I should see \"Media Library\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line 13 - testRunner.And("the status should be 200 \"OK\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 16 - testRunner.When("I go to \"admin/media/create\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line hidden - TechTalk.SpecFlow.Table table1 = new TechTalk.SpecFlow.Table(new string[] { - "name", - "value"}); - table1.AddRow(new string[] { - "Name", - "Hello World"}); -#line 17 - testRunner.And("I fill in", ((string)(null)), table1, "And "); -#line 20 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 21 - testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 22 - testRunner.Then("I should see \"Media\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 23 - testRunner.And("I should see \"Hello World\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 24 - testRunner.And("the status should be 200 \"OK\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 27 - testRunner.When("I go to \"admin/media/edit?name=..\\..\\bin&mediaPath=..\\..\\bin\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 28 - testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 29 - testRunner.Then("I should see \"Media\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 30 - testRunner.And("I should see \"Editing failed: Invalid path\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 31 - testRunner.And("the status should be 200 \"OK\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("the status should be 200 \"OK\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden this.ScenarioCleanup(); } diff --git a/src/Orchard.Specs/packages.config b/src/Orchard.Specs/packages.config index 8ec4801a544..d7cfa4c7a51 100644 --- a/src/Orchard.Specs/packages.config +++ b/src/Orchard.Specs/packages.config @@ -17,4 +17,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Tests.Modules/Orchard.Tests.Modules.csproj b/src/Orchard.Tests.Modules/Orchard.Tests.Modules.csproj index 633956c5d30..dad7f771fd0 100644 --- a/src/Orchard.Tests.Modules/Orchard.Tests.Modules.csproj +++ b/src/Orchard.Tests.Modules/Orchard.Tests.Modules.csproj @@ -77,11 +77,8 @@ ..\packages\Orchard.FluentPath.1.0.0.1\lib\FluentPath.dll - - ..\packages\SharpZipLib.1.3.1\lib\net45\ICSharpCode.SharpZipLib.dll - - - ..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll + + ..\packages\SharpZipLib.1.3.3\lib\net45\ICSharpCode.SharpZipLib.dll ..\packages\IronRuby.1.1.3\lib\IronRuby.dll diff --git a/src/Orchard.Tests.Modules/Recipes/Services/RecipeManagerTests.cs b/src/Orchard.Tests.Modules/Recipes/Services/RecipeManagerTests.cs index 9ead3ec3a5c..6510fe3b6c8 100644 --- a/src/Orchard.Tests.Modules/Recipes/Services/RecipeManagerTests.cs +++ b/src/Orchard.Tests.Modules/Recipes/Services/RecipeManagerTests.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Configuration; using System.IO; using System.Linq; using System.Xml; @@ -14,6 +13,7 @@ using Orchard.Environment.Extensions.Loaders; using Orchard.FileSystems.AppData; using Orchard.FileSystems.WebSite; +using Orchard.Mvc; using Orchard.Recipes.Events; using Orchard.Recipes.Models; using Orchard.Recipes.Services; @@ -93,6 +93,7 @@ public override void Register(ContainerBuilder builder) { builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType().As(); + builder.RegisterType().As(); } public override void Init() { diff --git a/src/Orchard.Tests/Localization/CurrentCultureWorkContextTests.cs b/src/Orchard.Tests/Localization/CurrentCultureWorkContextTests.cs index 7cb8741f9f1..db14dc7cad1 100644 --- a/src/Orchard.Tests/Localization/CurrentCultureWorkContextTests.cs +++ b/src/Orchard.Tests/Localization/CurrentCultureWorkContextTests.cs @@ -1,7 +1,13 @@ -using Autofac; +using System.IO; +using Autofac; +using NHibernate; using NUnit.Framework; +using Orchard.Caching; +using Orchard.Data; +using Orchard.Localization.Records; using Orchard.Localization.Services; using Orchard.Mvc; +using Orchard.Tests.ContentManagement; using Orchard.Tests.Stubs; namespace Orchard.Tests.Localization { @@ -10,25 +16,56 @@ public class CurrentCultureWorkContextTests { private IContainer _container; private IWorkContextStateProvider _currentCultureStateProvider; private WorkContext _workContext; + private ISessionFactory _sessionFactory; + private ISession _session; + private string _databaseFileName; + private const string _testCulture = "fr-CA"; + + [TestFixtureSetUp] + public void InitFixture() { + _databaseFileName = Path.GetTempFileName(); + _sessionFactory = DataUtility.CreateSessionFactory( + _databaseFileName, + typeof(CultureRecord)); + } [SetUp] public void Init() { + _session = _sessionFactory.OpenSession(); + var builder = new ContainerBuilder(); _workContext = new StubWorkContext(); - builder.RegisterInstance(new StubCultureSelector("fr-CA")).As(); + builder.RegisterInstance(new StubCultureSelector(_testCulture)).As(); builder.RegisterInstance(new StubHttpContext("~/")); builder.RegisterInstance(_workContext); builder.RegisterType().As(); builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>)); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As(); + builder.RegisterType().As(); + _session = _sessionFactory.OpenSession(); + builder.RegisterInstance(new TestTransactionManager(_session)).As(); _container = builder.Build(); _currentCultureStateProvider = _container.Resolve(); + _container.Resolve().AddCulture(_testCulture); + } + + [TearDown] + public void Term() { + _session.Close(); + } + + [TestFixtureTearDown] + public void TermFixture() { + File.Delete(_databaseFileName); } [Test] public void CultureManagerReturnsCultureFromSelectors() { var actualCulture = _currentCultureStateProvider.Get("CurrentCulture")(_workContext); - var expectedCulture = "fr-CA"; - Assert.That(actualCulture, Is.EqualTo(expectedCulture)); + Assert.That(actualCulture, Is.EqualTo(_testCulture)); } } } \ No newline at end of file diff --git a/src/Orchard.Tests/Localization/DefaultDateFormatterTests.cs b/src/Orchard.Tests/Localization/DefaultDateFormatterTests.cs index a2135f09c03..9a5cf113d86 100644 --- a/src/Orchard.Tests/Localization/DefaultDateFormatterTests.cs +++ b/src/Orchard.Tests/Localization/DefaultDateFormatterTests.cs @@ -13,7 +13,7 @@ namespace Orchard.Tests.Localization { [TestFixture()] - [Category("longrunning")] + [Category("longrunning")] public class DefaultDateFormatterTests { [SetUp] diff --git a/src/Orchard.Tests/Orchard.Framework.Tests.csproj b/src/Orchard.Tests/Orchard.Framework.Tests.csproj index 53cc94f79f5..313c19cdc60 100644 --- a/src/Orchard.Tests/Orchard.Framework.Tests.csproj +++ b/src/Orchard.Tests/Orchard.Framework.Tests.csproj @@ -142,7 +142,7 @@ ..\..\lib\sqlce\System.Data.SqlServerCe.dll True - + ..\packages\Microsoft.AspNet.WebApi.Client.5.2.7\lib\net45\System.Net.Http.Formatting.dll diff --git a/src/Orchard.Tests/Storage/FileSystemStorageProviderTests.cs b/src/Orchard.Tests/Storage/FileSystemStorageProviderTests.cs index 80885263e4e..1d4250ed65d 100644 --- a/src/Orchard.Tests/Storage/FileSystemStorageProviderTests.cs +++ b/src/Orchard.Tests/Storage/FileSystemStorageProviderTests.cs @@ -1,10 +1,9 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using NUnit.Framework; -using System; -using Orchard.Environment; using Orchard.Environment.Configuration; using Orchard.FileSystems.Media; @@ -215,8 +214,8 @@ public void RenameFileTakesShortPathWithAnyKindOfSlash() { [Test] public void GetFileFailsInInvalidPath() { - Assert.That(() => _storageProvider.GetFile(@"../InvalidFile.txt"), Throws.InstanceOf(typeof(ArgumentException))); - Assert.That(() => _storageProvider.GetFile(@"../../InvalidFile.txt"), Throws.InstanceOf(typeof(ArgumentException))); + Assert.That(() => _storageProvider.GetFile(@"../InvalidFile.txt"), Throws.InstanceOf(typeof(OrchardException))); + Assert.That(() => _storageProvider.GetFile(@"../../InvalidFile.txt"), Throws.InstanceOf(typeof(OrchardException))); // Valid get one level up within the storage provider domain _storageProvider.CreateFile(@"test.txt"); @@ -226,8 +225,8 @@ public void GetFileFailsInInvalidPath() { [Test] public void ListFilesFailsInInvalidPath() { - Assert.That(() => _storageProvider.ListFiles(@"../InvalidFolder"), Throws.InstanceOf(typeof(ArgumentException))); - Assert.That(() => _storageProvider.ListFiles(@"../../InvalidFolder"), Throws.InstanceOf(typeof(ArgumentException))); + Assert.That(() => _storageProvider.ListFiles(@"../InvalidFolder"), Throws.InstanceOf(typeof(OrchardException))); + Assert.That(() => _storageProvider.ListFiles(@"../../InvalidFolder"), Throws.InstanceOf(typeof(OrchardException))); // Valid get one level up within the storage provider domain Assert.That(_storageProvider.ListFiles(@"SubFolder1"), Is.Not.Null); @@ -236,8 +235,8 @@ public void ListFilesFailsInInvalidPath() { [Test] public void ListFoldersFailsInInvalidPath() { - Assert.That(() => _storageProvider.ListFolders(@"../InvalidFolder"), Throws.InstanceOf(typeof(ArgumentException))); - Assert.That(() => _storageProvider.ListFolders(@"../../InvalidFolder"), Throws.InstanceOf(typeof(ArgumentException))); + Assert.That(() => _storageProvider.ListFolders(@"../InvalidFolder"), Throws.InstanceOf(typeof(OrchardException))); + Assert.That(() => _storageProvider.ListFolders(@"../../InvalidFolder"), Throws.InstanceOf(typeof(OrchardException))); // Valid get one level up within the storage provider domain Assert.That(_storageProvider.ListFolders(@"SubFolder1"), Is.Not.Null); @@ -255,8 +254,8 @@ public void TryCreateFolderFailsInInvalidPath() { [Test] public void CreateFolderFailsInInvalidPath() { - Assert.That(() => _storageProvider.CreateFolder(@"../InvalidFolder1"), Throws.InstanceOf(typeof(ArgumentException))); - Assert.That(() => _storageProvider.CreateFolder(@"../../InvalidFolder1"), Throws.InstanceOf(typeof(ArgumentException))); + Assert.That(() => _storageProvider.CreateFolder(@"../InvalidFolder1"), Throws.InstanceOf(typeof(OrchardException))); + Assert.That(() => _storageProvider.CreateFolder(@"../../InvalidFolder1"), Throws.InstanceOf(typeof(OrchardException))); // Valid create one level up within the storage provider domain _storageProvider.CreateFolder(@"SubFolder1\..\ValidFolder1"); @@ -265,8 +264,8 @@ public void CreateFolderFailsInInvalidPath() { [Test] public void DeleteFolderFailsInInvalidPath() { - Assert.That(() => _storageProvider.DeleteFolder(@"../InvalidFolder1"), Throws.InstanceOf(typeof(ArgumentException))); - Assert.That(() => _storageProvider.DeleteFolder(@"../../InvalidFolder1"), Throws.InstanceOf(typeof(ArgumentException))); + Assert.That(() => _storageProvider.DeleteFolder(@"../InvalidFolder1"), Throws.InstanceOf(typeof(OrchardException))); + Assert.That(() => _storageProvider.DeleteFolder(@"../../InvalidFolder1"), Throws.InstanceOf(typeof(OrchardException))); // Valid create one level up within the storage provider domain Assert.That(GetFolder("SubFolder1"), Is.Not.Null); @@ -277,8 +276,8 @@ public void DeleteFolderFailsInInvalidPath() { [Test] public void RenameFolderFailsInInvalidPath() { Assert.That(GetFolder(@"SubFolder1/SubSubFolder1"), Is.Not.Null); - Assert.That(() => _storageProvider.RenameFolder(@"SubFolder1", @"../SubSubFolder1"), Throws.InstanceOf(typeof(ArgumentException))); - Assert.That(() => _storageProvider.RenameFolder(@"SubFolder1", @"../../SubSubFolder1"), Throws.InstanceOf(typeof(ArgumentException))); + Assert.That(() => _storageProvider.RenameFolder(@"SubFolder1", @"../SubSubFolder1"), Throws.InstanceOf(typeof(OrchardException))); + Assert.That(() => _storageProvider.RenameFolder(@"SubFolder1", @"../../SubSubFolder1"), Throws.InstanceOf(typeof(OrchardException))); // Valid move one level up within the storage provider domain _storageProvider.RenameFolder(@"SubFolder1\SubSubFolder1", @"SubFolder1\..\SubSubFolder1"); @@ -291,8 +290,8 @@ public void RenameFolderFailsInInvalidPath() { [Test] public void DeleteFileFailsInInvalidPath() { - Assert.That(() => _storageProvider.DeleteFile(@"../test.txt"), Throws.InstanceOf(typeof(ArgumentException))); - Assert.That(() => _storageProvider.DeleteFile(@"../test.txt"), Throws.InstanceOf(typeof(ArgumentException))); + Assert.That(() => _storageProvider.DeleteFile(@"../test.txt"), Throws.InstanceOf(typeof(OrchardException))); + Assert.That(() => _storageProvider.DeleteFile(@"../test.txt"), Throws.InstanceOf(typeof(OrchardException))); // Valid move one level up within the storage provider domain _storageProvider.CreateFile(@"test.txt"); @@ -308,8 +307,8 @@ public void DeleteFileFailsInInvalidPath() { [Test] public void RenameFileFailsInInvalidPath() { - Assert.That(() => _storageProvider.RenameFile(@"../test.txt", "invalid.txt"), Throws.InstanceOf(typeof(ArgumentException))); - Assert.That(() => _storageProvider.RenameFile(@"../test.txt", "invalid.txt"), Throws.InstanceOf(typeof(ArgumentException))); + Assert.That(() => _storageProvider.RenameFile(@"../test.txt", "invalid.txt"), Throws.InstanceOf(typeof(OrchardException))); + Assert.That(() => _storageProvider.RenameFile(@"../test.txt", "invalid.txt"), Throws.InstanceOf(typeof(OrchardException))); // Valid move one level up within the storage provider domain _storageProvider.CreateFile(@"test.txt"); @@ -322,8 +321,8 @@ public void RenameFileFailsInInvalidPath() { [Test] public void CreateFileFailsInInvalidPath() { - Assert.That(() => _storageProvider.CreateFile(@"../InvalidFolder1.txt"), Throws.InstanceOf(typeof(ArgumentException))); - Assert.That(() => _storageProvider.CreateFile(@"../../InvalidFolder1.txt"), Throws.InstanceOf(typeof(ArgumentException))); + Assert.That(() => _storageProvider.CreateFile(@"../InvalidFolder1.txt"), Throws.InstanceOf(typeof(OrchardException))); + Assert.That(() => _storageProvider.CreateFile(@"../../InvalidFolder1.txt"), Throws.InstanceOf(typeof(OrchardException))); // Valid create one level up within the storage provider domain _storageProvider.CreateFile(@"SubFolder1\..\ValidFolder1.txt"); @@ -335,8 +334,8 @@ public void SaveStreamFailsInInvalidPath() { _storageProvider.CreateFile(@"test.txt"); using (Stream stream = GetFile("test.txt").OpenRead()) { - Assert.That(() => _storageProvider.SaveStream(@"../newTest.txt", stream), Throws.InstanceOf(typeof(ArgumentException))); - Assert.That(() => _storageProvider.SaveStream(@"../../newTest.txt", stream), Throws.InstanceOf(typeof(ArgumentException))); + Assert.That(() => _storageProvider.SaveStream(@"../newTest.txt", stream), Throws.InstanceOf(typeof(OrchardException))); + Assert.That(() => _storageProvider.SaveStream(@"../../newTest.txt", stream), Throws.InstanceOf(typeof(OrchardException))); // Valid create one level up within the storage provider domain _storageProvider.SaveStream(@"SubFolder1\..\newTest.txt", stream); diff --git a/src/Orchard.Web/Config/HostComponents.config b/src/Orchard.Web/Config/HostComponents.config index 888cdb0a697..c0da7b4d5be 100644 --- a/src/Orchard.Web/Config/HostComponents.config +++ b/src/Orchard.Web/Config/HostComponents.config @@ -9,6 +9,14 @@ + + + + + + + @@ -80,6 +88,14 @@ + + + + + + + diff --git a/src/Orchard.Web/Core/Common/Migrations.cs b/src/Orchard.Web/Core/Common/Migrations.cs index ff4e0bb4568..65565f04531 100644 --- a/src/Orchard.Web/Core/Common/Migrations.cs +++ b/src/Orchard.Web/Core/Common/Migrations.cs @@ -10,6 +10,15 @@ namespace Orchard.Core.Common { public class Migrations : DataMigrationImpl { private readonly IRepository _identityPartRepository; + /// + /// When upgrading from "1.10.x" branch code committed after 1.10.3 to "dev" branch code or 1.11, merge + /// conflicts between "1.10.x" and "dev" caused by running the same migration steps in a different order need to + /// be resolved by instructing this migration to decide which steps need to be executed. If you're upgrading + /// under these conditions and your pre-upgrade migration version is 7 or 8, use HostComponents.config to + /// override one of these properties to true. + /// + public bool IsUpgradingFromOrchard_1_10_x_Version_7 { get; set; } + public bool IsUpgradingFromOrchard_1_10_x_Version_8 { get; set; } public Migrations(IRepository identityPartRepository) { _identityPartRepository = identityPartRepository; @@ -35,7 +44,7 @@ public int Create() { table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_{nameof(CommonPartRecord.ModifiedUtc)}", nameof(CommonPartRecord.ModifiedUtc)); table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_{nameof(CommonPartRecord.PublishedUtc)}", nameof(CommonPartRecord.PublishedUtc)); // This originally in UpdateFrom7 - table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_Container_id","Container_id"); + table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_Container_id", "Container_id"); // This originally in UpdateFrom8 table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_OwnedBy_ByCreation", nameof(CommonPartRecord.OwnerId), @@ -66,6 +75,7 @@ public int Create() { .ContentPartRecord() .Column("Identifier", column => column.WithLength(255))) .AlterTable(nameof(IdentityPartRecord), table => table + // This originally in UpdateFrom6 .CreateIndex($"IDX_{nameof(IdentityPartRecord)}_{nameof(IdentityPartRecord.Identifier)}", nameof(IdentityPartRecord.Identifier))); ContentDefinitionManager.AlterPartDefinition("BodyPart", builder => builder @@ -79,7 +89,7 @@ public int Create() { ContentDefinitionManager.AlterPartDefinition("IdentityPart", builder => builder .Attachable() .WithDescription("Automatically generates a unique identity for the content item, which is required in import/export scenarios where one content item references another.")); - + return 9; } @@ -155,61 +165,77 @@ public int UpdateFrom5() { } public int UpdateFrom6() { - SchemaBuilder.AlterTable(nameof(IdentityPartRecord), table => table - .CreateIndex($"IDX_{nameof(IdentityPartRecord)}_{nameof(IdentityPartRecord.Identifier)}", nameof(IdentityPartRecord.Identifier))); + AddIndexForIdentityPartRecordIdentifier(); return 7; } public int UpdateFrom7() { - // The Container_Id is basically a foreign key, used in several queries - SchemaBuilder.AlterTable(nameof(CommonPartRecord), table => { - table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_Container_id", - "Container_id"); - }); + AddIndexForCommonPartRecordContainerId(); return 8; } public int UpdateFrom8() { - // Studying SQL Server query execution plans we noticed that when the system - // tries to find content items for requests such as - // "The items of type TTT owned by me, ordered from the most recent" - // the existing indexes are not used. SQL Server does an index scan on the - // Primary key for CommonPartRecord. This may lead to annoying deadlocks when - // there are two concurrent transactions that are doing both this kind of query - // as well as an update (or insert) in the CommonPartRecord. - // Tests show that this can be easily fixed by adding a non-clustered index - // with these keys: OwnerId, {one of PublishedUTC, ModifiedUTC, CreatedUTC}. - // That means we need three indexes (one for each DateTime) to support ordering - // on either of them. - - // The queries we analyzed look like (in pseudo sql) - // SELECT TOP (N) * - // FROM - // ContentItemVersionRecord this_ - // inner join ContentItemRecord contentite1_ on this_.ContentItemRecord_id=contentite1_.Id - // inner join CommonPartRecord commonpart2_ on contentite1_.Id=commonpart2.Id - // left outer join ContentTypeRecord contenttyp6_ on contentite1_.ContentType_id=contenttyp6_.Id - // WHERE - // contentite1.ContentType_id = {TTT} - // and commonpart2_.OwnerId = {userid} - // and this_.Published = 1 - // ORDER BY - // commonpart2_PublishedUtc desc + if (IsUpgradingFromOrchard_1_10_x_Version_7) { + AddIndexForIdentityPartRecordIdentifier(); + } + else if (IsUpgradingFromOrchard_1_10_x_Version_8) { + AddIndexForCommonPartRecordContainerId(); + } + else { + // This change was originally UpdateFrom6 on 1.10.x and UpdateFrom8 on dev. + + // Studying SQL Server query execution plans we noticed that when the system tries to find content items for + // requests such as "The items of type TTT owned by me, ordered from the most recent" the existing indexes + // are not used. SQL Server does an index scan on the Primary key for CommonPartRecord. This may lead to + // annoying deadlocks when there are two concurrent transactions that are doing both this kind of query as + // well as an update (or insert) in the CommonPartRecord. Tests show that this can be easily fixed by adding + // a non-clustered index with these keys: OwnerId, {one of PublishedUTC, ModifiedUTC, CreatedUTC}. That + // means we need three indexes (one for each DateTime) to support ordering on either of them. + + // The queries we analyzed look like (in pseudo sql) + // SELECT TOP (N) * + // FROM + // ContentItemVersionRecord this_ + // inner join ContentItemRecord contentite1_ on this_.ContentItemRecord_id=contentite1_.Id + // inner join CommonPartRecord commonpart2_ on contentite1_.Id=commonpart2.Id + // left outer join ContentTypeRecord contenttyp6_ on contentite1_.ContentType_id=contenttyp6_.Id + // WHERE + // contentite1.ContentType_id = {TTT} + // and commonpart2_.OwnerId = {userid} + // and this_.Published = 1 + // ORDER BY + // commonpart2_PublishedUtc desc + var createdUtcIndexName = $"IDX_{nameof(CommonPartRecord)}_OwnedBy_ByCreation"; + var modifiedUtcIndexName = $"IDX_{nameof(CommonPartRecord)}_OwnedBy_ByModification"; + var publishedUtcIndexName = $"IDX_{nameof(CommonPartRecord)}_OwnedBy_ByPublication"; + + SchemaBuilder.AlterTable(nameof(CommonPartRecord), table => { + table.CreateIndex(createdUtcIndexName, nameof(CommonPartRecord.OwnerId), nameof(CommonPartRecord.CreatedUtc)); + table.CreateIndex(modifiedUtcIndexName, nameof(CommonPartRecord.OwnerId), nameof(CommonPartRecord.ModifiedUtc)); + table.CreateIndex(publishedUtcIndexName, nameof(CommonPartRecord.OwnerId), nameof(CommonPartRecord.PublishedUtc)); + }); + } - SchemaBuilder.AlterTable(nameof(CommonPartRecord), table => { - table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_OwnedBy_ByCreation", - nameof(CommonPartRecord.OwnerId), - nameof(CommonPartRecord.CreatedUtc)); - table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_OwnedBy_ByModification", - nameof(CommonPartRecord.OwnerId), - nameof(CommonPartRecord.ModifiedUtc)); - table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_OwnedBy_ByPublication", - nameof(CommonPartRecord.OwnerId), - nameof(CommonPartRecord.PublishedUtc)); - }); return 9; } + + // This change was originally UpdateFrom7 on 1.10.x and UpdateFrom6 on dev. + private void AddIndexForIdentityPartRecordIdentifier() { + var indexName = $"IDX_{nameof(IdentityPartRecord)}_{nameof(IdentityPartRecord.Identifier)}"; + + SchemaBuilder.AlterTable(nameof(IdentityPartRecord), table => table.CreateIndex( + indexName, + nameof(IdentityPartRecord.Identifier))); + } + + // This change was originally UpdateFrom8 on 1.10.x and UpdateFrom7 on dev. + private void AddIndexForCommonPartRecordContainerId() { + var indexName = $"IDX_{nameof(CommonPartRecord)}_Container_id"; + + // Container_Id is used in several queries like a foreign key. + SchemaBuilder.AlterTable(nameof(CommonPartRecord), table => table.CreateIndex(indexName, "Container_id")); + } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Core/Common/OwnerEditor/OwnerEditorDriver.cs b/src/Orchard.Web/Core/Common/OwnerEditor/OwnerEditorDriver.cs index 3707a35a455..03cab2834ad 100644 --- a/src/Orchard.Web/Core/Common/OwnerEditor/OwnerEditorDriver.cs +++ b/src/Orchard.Web/Core/Common/OwnerEditor/OwnerEditorDriver.cs @@ -35,7 +35,7 @@ protected override DriverResult Editor(CommonPart part, dynamic shapeHelper) { protected override DriverResult Editor(CommonPart part, IUpdateModel updater, dynamic shapeHelper) { var currentUser = _authenticationService.GetAuthenticatedUser(); - if (!_authorizationService.TryCheckAccess(StandardPermissions.SiteOwner, currentUser, part)) { + if (!_authorizationService.TryCheckAccess(OwnerEditorPermissions.MayEditContentOwner, currentUser, part)) { return null; } diff --git a/src/Orchard.Web/Core/Common/OwnerEditor/OwnerEditorPermissions.cs b/src/Orchard.Web/Core/Common/OwnerEditor/OwnerEditorPermissions.cs new file mode 100644 index 00000000000..40bd7c46aef --- /dev/null +++ b/src/Orchard.Web/Core/Common/OwnerEditor/OwnerEditorPermissions.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using Orchard.Environment.Extensions.Models; +using Orchard.Security; +using Orchard.Security.Permissions; + +namespace Orchard.Core.Common.OwnerEditor { + public class OwnerEditorPermissions : IPermissionProvider { + + public static readonly Permission MayEditContentOwner = new Permission { + Description = "Edit the Owner of content items", + Name = "MayEditContentOwner", + ImpliedBy = new[] { StandardPermissions.SiteOwner } }; + + public virtual Feature Feature { get; set; } + + public IEnumerable GetDefaultStereotypes() { + return new[] {new PermissionStereotype { + Name = "Administrator", + Permissions = new[] { MayEditContentOwner } + } }; + } + + public IEnumerable GetPermissions() { + return new[] { MayEditContentOwner }; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Core/Common/Views/EditorTemplates/Fields.Common.Text.Edit.cshtml b/src/Orchard.Web/Core/Common/Views/EditorTemplates/Fields.Common.Text.Edit.cshtml index b91ef2c637d..75e0a37bd50 100644 --- a/src/Orchard.Web/Core/Common/Views/EditorTemplates/Fields.Common.Text.Edit.cshtml +++ b/src/Orchard.Web/Core/Common/Views/EditorTemplates/Fields.Common.Text.Edit.cshtml @@ -9,7 +9,7 @@ @Html.ValidationMessageFor(m => m.Text) } else { - @Display.Body_Editor(Text: Model.Text, EditorFlavor: Model.Settings.Flavor, Required: Model.Settings.Required, ContentItem: Model.ContentItem, Placeholder: Model.Settings.Placeholder) + @Display.Body_Editor(Text: Model.Text, EditorFlavor: Model.Settings.Flavor, Required: Model.Settings.Required, ContentItem: Model.ContentItem, Placeholder: Model.Settings.Placeholder, Field: Model.Field) } @if (HasText(Model.Settings.Hint)) { @Model.Settings.Hint diff --git a/src/Orchard.Web/Core/Common/Views/EditorTemplates/Parts.Common.Body.cshtml b/src/Orchard.Web/Core/Common/Views/EditorTemplates/Parts.Common.Body.cshtml index 1e3e488a679..785d436ee35 100644 --- a/src/Orchard.Web/Core/Common/Views/EditorTemplates/Parts.Common.Body.cshtml +++ b/src/Orchard.Web/Core/Common/Views/EditorTemplates/Parts.Common.Body.cshtml @@ -2,6 +2,6 @@ @using Orchard.Core.Common.ViewModels;
- @Display.Body_Editor(Text: Model.Text, EditorFlavor: Model.EditorFlavor, Required: false, AutoFocus: false, ContentItem: Model.BodyPart.ContentItem) + @Display.Body_Editor(Text: Model.Text, EditorFlavor: Model.EditorFlavor, Required: false, AutoFocus: false, ContentItem: Model.BodyPart.ContentItem, Part: Model.BodyPart) @Html.ValidationMessageFor(m => m.Text)
\ No newline at end of file diff --git a/src/Orchard.Web/Core/Navigation/Services/DefaultMenuProvider.cs b/src/Orchard.Web/Core/Navigation/Services/DefaultMenuProvider.cs index 036801c0512..b33ba88da55 100644 --- a/src/Orchard.Web/Core/Navigation/Services/DefaultMenuProvider.cs +++ b/src/Orchard.Web/Core/Navigation/Services/DefaultMenuProvider.cs @@ -1,4 +1,5 @@ -using System.Web; +using System.Collections.Generic; +using System.Web; using Orchard.ContentManagement; using Orchard.ContentManagement.Aspects; using Orchard.Core.Navigation.Models; @@ -11,29 +12,48 @@ public class DefaultMenuProvider : IMenuProvider { public DefaultMenuProvider(IContentManager contentManager) { _contentManager = contentManager; + + _menuPartsMemory = new Dictionary>(); } + // Prevent doing the same query for MenuParts more than once on a same request + // in case we are building the same menu several times. + private Dictionary> _menuPartsMemory; + public void GetMenu(IContent menu, NavigationBuilder builder) { - var menuParts = _contentManager - .Query() - .Where(x => x.MenuId == menu.Id) - .List(); + if (!_menuPartsMemory.ContainsKey(menu.Id)) { + _menuPartsMemory[menu.Id] = _contentManager + .Query() + .Where(x => x.MenuId == menu.Id) + .List(); + } + var menuParts = _menuPartsMemory[menu.Id]; foreach (var menuPart in menuParts) { if (menuPart != null) { var part = menuPart; - string culture = null; - // fetch the culture of the content menu item, if any - var localized = part.As(); - if (localized != null) { - culture = localized.Culture; + var showItem = true; + // If the menu item is a ContentMenuItemPart (from Orchard.ContentPicker), check the ContentItem is published. + // If there is no published version of the ContentItem, the item must not be added to NavigationBuilder. + var cmip = ((dynamic)part).ContentMenuItemPart; + if (cmip != null) { + showItem = cmip.Content != null; } - if (part.Is()) - builder.Add(new LocalizedString(HttpUtility.HtmlEncode(part.MenuText)), part.MenuPosition, item => item.Url(part.As().Url).Content(part).Culture(culture).Permission(Contents.Permissions.ViewContent)); - else - builder.Add(new LocalizedString(HttpUtility.HtmlEncode(part.MenuText)), part.MenuPosition, item => item.Action(_contentManager.GetItemMetadata(part.ContentItem).DisplayRouteValues).Content(part).Culture(culture).Permission(Contents.Permissions.ViewContent)); + if (showItem) { + string culture = null; + // fetch the culture of the content menu item, if any + var localized = part.As(); + if (localized != null) { + culture = localized.Culture; + } + + if (part.Is()) + builder.Add(new LocalizedString(HttpUtility.HtmlEncode(part.MenuText)), part.MenuPosition, item => item.Url(part.As().Url).Content(part).Culture(culture).Permission(Contents.Permissions.ViewContent)); + else + builder.Add(new LocalizedString(HttpUtility.HtmlEncode(part.MenuText)), part.MenuPosition, item => item.Action(_contentManager.GetItemMetadata(part.ContentItem).DisplayRouteValues).Content(part).Culture(culture).Permission(Contents.Permissions.ViewContent)); + } } } } diff --git a/src/Orchard.Web/Core/Navigation/Views/EditorTemplates/Parts.MenuWidget.Edit.cshtml b/src/Orchard.Web/Core/Navigation/Views/EditorTemplates/Parts.MenuWidget.Edit.cshtml index 048775c9eb5..c7a79c97a0b 100644 --- a/src/Orchard.Web/Core/Navigation/Views/EditorTemplates/Parts.MenuWidget.Edit.cshtml +++ b/src/Orchard.Web/Core/Navigation/Views/EditorTemplates/Parts.MenuWidget.Edit.cshtml @@ -13,7 +13,7 @@ @Html.SelectOption(Model.CurrentMenuId, menu.Id, Html.ItemDisplayText(menu, false).ToString()) if (Model.CurrentMenuId == menu.Id) { selectedMenuId = menu.Id; - } + } } @if (selectedMenuId != -1) { diff --git a/src/Orchard.Web/Core/Orchard.Core.csproj b/src/Orchard.Web/Core/Orchard.Core.csproj index a8e3e4228fe..aea063fc7a9 100644 --- a/src/Orchard.Web/Core/Orchard.Core.csproj +++ b/src/Orchard.Web/Core/Orchard.Core.csproj @@ -63,10 +63,14 @@ ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + ..\..\packages\NHibernate.5.3.10\lib\net461\NHibernate.dll + 3.5 + @@ -99,6 +103,7 @@ + @@ -605,13 +610,11 @@ + - - - 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) diff --git a/src/Orchard.Web/Core/Web.config b/src/Orchard.Web/Core/Web.config index 2afc63834c0..7e7a529218d 100644 --- a/src/Orchard.Web/Core/Web.config +++ b/src/Orchard.Web/Core/Web.config @@ -39,22 +39,22 @@ - - - - - - - - + + + + + + + + - - - + + + - - - + + + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Core/packages.config b/src/Orchard.Web/Core/packages.config index 0938ac40a9c..c9ae65df284 100644 --- a/src/Orchard.Web/Core/packages.config +++ b/src/Orchard.Web/Core/packages.config @@ -5,4 +5,5 @@ + diff --git a/src/Orchard.Web/Modules/Lucene/Lucene.csproj b/src/Orchard.Web/Modules/Lucene/Lucene.csproj index e8e23cd6300..286e8f42ba6 100644 --- a/src/Orchard.Web/Modules/Lucene/Lucene.csproj +++ b/src/Orchard.Web/Modules/Lucene/Lucene.csproj @@ -55,8 +55,8 @@ false - - ..\..\..\packages\SharpZipLib.1.3.1\lib\net45\ICSharpCode.SharpZipLib.dll + + ..\..\..\packages\SharpZipLib.1.3.3\lib\net45\ICSharpCode.SharpZipLib.dll ..\..\..\packages\Lucene.Net.3.0.3\lib\NET40\Lucene.Net.dll diff --git a/src/Orchard.Web/Modules/Lucene/Web.config b/src/Orchard.Web/Modules/Lucene/Web.config index ec624b0db27..8af71443761 100644 --- a/src/Orchard.Web/Modules/Lucene/Web.config +++ b/src/Orchard.Web/Modules/Lucene/Web.config @@ -38,24 +38,24 @@ - - - - - - - - + + + + + + + + - - - + + + - - - + + + - + @@ -68,8 +68,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Markdown/Web.config b/src/Orchard.Web/Modules/Markdown/Web.config index 854be8b67fa..256049a39a3 100644 --- a/src/Orchard.Web/Modules/Markdown/Web.config +++ b/src/Orchard.Web/Modules/Markdown/Web.config @@ -39,24 +39,24 @@ - - - - - - - - + + + + + + + + - - - + + + - - - + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Alias/Web.config b/src/Orchard.Web/Modules/Orchard.Alias/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.Alias/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Alias/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.AntiSpam/Orchard.AntiSpam.csproj b/src/Orchard.Web/Modules/Orchard.AntiSpam/Orchard.AntiSpam.csproj index 02aed008829..11c509da24c 100644 --- a/src/Orchard.Web/Modules/Orchard.AntiSpam/Orchard.AntiSpam.csproj +++ b/src/Orchard.Web/Modules/Orchard.AntiSpam/Orchard.AntiSpam.csproj @@ -259,4 +259,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.AntiSpam/Web.config b/src/Orchard.Web/Modules/Orchard.AntiSpam/Web.config index 854be8b67fa..256049a39a3 100644 --- a/src/Orchard.Web/Modules/Orchard.AntiSpam/Web.config +++ b/src/Orchard.Web/Modules/Orchard.AntiSpam/Web.config @@ -39,24 +39,24 @@ - - - - - - - - + + + + + + + + - - - + + + - - - + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.AntiSpam/packages.config b/src/Orchard.Web/Modules/Orchard.AntiSpam/packages.config index 2ae22b193cd..51c3aaef7f0 100644 --- a/src/Orchard.Web/Modules/Orchard.AntiSpam/packages.config +++ b/src/Orchard.Web/Modules/Orchard.AntiSpam/packages.config @@ -6,4 +6,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.ArchiveLater/Web.config b/src/Orchard.Web/Modules/Orchard.ArchiveLater/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.ArchiveLater/Web.config +++ b/src/Orchard.Web/Modules/Orchard.ArchiveLater/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.AuditTrail/Web.config b/src/Orchard.Web/Modules/Orchard.AuditTrail/Web.config index 4a8db83a65d..8c9f9b2f355 100644 --- a/src/Orchard.Web/Modules/Orchard.AuditTrail/Web.config +++ b/src/Orchard.Web/Modules/Orchard.AuditTrail/Web.config @@ -29,6 +29,7 @@ + @@ -40,22 +41,22 @@ - - + + - - + + - - + + - - + + - + @@ -70,8 +71,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.AuditTrail/packages.config b/src/Orchard.Web/Modules/Orchard.AuditTrail/packages.config index 333172e4f21..bf96ae8b5ff 100644 --- a/src/Orchard.Web/Modules/Orchard.AuditTrail/packages.config +++ b/src/Orchard.Web/Modules/Orchard.AuditTrail/packages.config @@ -12,4 +12,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Autoroute/Web.config b/src/Orchard.Web/Modules/Orchard.Autoroute/Web.config index 8f65a548900..cd0397645d6 100644 --- a/src/Orchard.Web/Modules/Orchard.Autoroute/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Autoroute/Web.config @@ -38,24 +38,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -68,8 +68,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Web.config b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Web.config index 6d5fd5e5b5b..cffe08d757f 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Web.config @@ -40,54 +40,54 @@ - - - + + + - - + + - - - + + + - - - + + + - - - + + + - - - - - - - - - - + + + + + + + + + + - - + + - + - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Azure/Orchard.Azure.csproj b/src/Orchard.Web/Modules/Orchard.Azure/Orchard.Azure.csproj index e6a7587454a..3e9a4b37e4d 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure/Orchard.Azure.csproj +++ b/src/Orchard.Web/Modules/Orchard.Azure/Orchard.Azure.csproj @@ -222,4 +222,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Azure/Web.config b/src/Orchard.Web/Modules/Orchard.Azure/Web.config index 9ecffde3720..af1baefa515 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Azure/Web.config @@ -43,40 +43,52 @@ --> - - - + + + - - + + - - - + + + - - - + + + - - - - + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -89,8 +101,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Azure/packages.config b/src/Orchard.Web/Modules/Orchard.Azure/packages.config index 68554c15c56..909cc51f835 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Azure/packages.config @@ -20,4 +20,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/AdminMenu.cs b/src/Orchard.Web/Modules/Orchard.Blogs/AdminMenu.cs index 2ff2071ab8d..4460dc8472a 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/AdminMenu.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/AdminMenu.cs @@ -42,7 +42,7 @@ private void BuildMenu(NavigationItemBuilder menu) { if (singleBlog != null) menu.Add(T("New Post"), "1.1", item => - item.Action("Create", "BlogPostAdmin", new {area = "Orchard.Blogs", blogId = singleBlog.Id}).Permission(Permissions.MetaListOwnBlogs)); + item.Action("Create", "BlogPostAdmin", new { area = "Orchard.Blogs", blogId = singleBlog.Id }).Permission(Permissions.MetaListOwnBlogs)); menu.Add(T("New Blog"), "1.2", item => diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/BlogPostLocalNavigationProvider.cs b/src/Orchard.Web/Modules/Orchard.Blogs/BlogPostLocalNavigationProvider.cs new file mode 100644 index 00000000000..5e20fbdaa24 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Blogs/BlogPostLocalNavigationProvider.cs @@ -0,0 +1,40 @@ +using Orchard.Blogs.Services; +using Orchard.Localization; +using Orchard.Security; +using Orchard.UI.Navigation; + +namespace Orchard.Blogs { + public class BlogPostsLocalNavigationProvider : INavigationProvider { + private readonly IBlogService _blogService; + private readonly IAuthorizationService _authorizationService; + private readonly IWorkContextAccessor _workContextAccessor; + + public BlogPostsLocalNavigationProvider( + IBlogService blogService, + IAuthorizationService authorizationService, + IWorkContextAccessor workContextAccessor) { + + T = NullLocalizer.Instance; + _blogService = blogService; + _authorizationService = authorizationService; + _workContextAccessor = workContextAccessor; + } + + public Localizer T { get; set; } + + public string MenuName { + get { return "blogposts-navigation"; } + } + + public void GetNavigation(NavigationBuilder builder) { + var blogId = 0; + int.TryParse(_workContextAccessor.GetContext().HttpContext.Request.RequestContext.RouteData.Values["blogId"]?.ToString(), out blogId); + if (blogId > 0) { + builder.Add(T("Blog posts"), + item => item.Action("Item", "BlogAdmin", new { area = "Orchard.Blogs", blogId }) + .LocalNav() + .Permission(Permissions.MetaListOwnBlogs)); + } + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogAdminController.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogAdminController.cs index 89590ff3ebc..8455f926368 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogAdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogAdminController.cs @@ -2,7 +2,6 @@ using System.Web.Mvc; using Orchard.Blogs.Extensions; using Orchard.Blogs.Models; -using Orchard.Blogs.Routing; using Orchard.Blogs.Services; using Orchard.ContentManagement; using Orchard.Data; @@ -13,6 +12,7 @@ using Orchard.UI.Navigation; using Orchard.UI.Notify; using Orchard.Settings; +using System.Collections.Generic; namespace Orchard.Blogs.Controllers { @@ -21,6 +21,7 @@ public class BlogAdminController : Controller, IUpdateModel { private readonly IBlogService _blogService; private readonly IBlogPostService _blogPostService; private readonly IContentManager _contentManager; + private readonly INavigationManager _navigationManager; private readonly ITransactionManager _transactionManager; private readonly ISiteService _siteService; @@ -29,6 +30,7 @@ public BlogAdminController( IBlogService blogService, IBlogPostService blogPostService, IContentManager contentManager, + INavigationManager navigationManager, ITransactionManager transactionManager, ISiteService siteService, IShapeFactory shapeFactory) { @@ -36,6 +38,7 @@ public BlogAdminController( _blogService = blogService; _blogPostService = blogPostService; _contentManager = contentManager; + _navigationManager = navigationManager; _transactionManager = transactionManager; _siteService = siteService; T = NullLocalizer.Instance; @@ -151,10 +154,10 @@ public ActionResult List() { list.AddRange(_blogService.Get(VersionOptions.Latest) .Where(x => Services.Authorizer.Authorize(Permissions.MetaListOwnBlogs, x)) .Select(b => { - var blog = Services.ContentManager.BuildDisplay(b, "SummaryAdmin"); - blog.TotalPostCount = _blogPostService.PostCount(b, VersionOptions.Latest); - return blog; - })); + var blog = Services.ContentManager.BuildDisplay(b, "SummaryAdmin"); + blog.TotalPostCount = _blogPostService.PostCount(b, VersionOptions.Latest); + return blog; + })); var viewModel = Services.New.ViewModel() .ContentItems(list); @@ -179,6 +182,18 @@ public ActionResult Item(int blogId, PagerParameters pagerParameters) { var totalItemCount = _blogPostService.PostCount(blogPart, VersionOptions.Latest); blog.Content.Add(Shape.Pager(pager).TotalItemCount(totalItemCount), "Content:after"); + // Adds LocalMenus; + var menuItems = _navigationManager.BuildMenu("blogposts-navigation"); + var request = Services.WorkContext.HttpContext.Request; + + // Set the currently selected path + Stack selectedPath = NavigationHelper.SetSelectedPath(menuItems, request, request.RequestContext.RouteData); + + // Populate local nav + dynamic localMenuShape = Shape.LocalMenu().MenuName("local-admin"); + // NavigationHelper.PopulateLocalMenu(Shape, localMenuShape, localMenuShape, selectedPath); + NavigationHelper.PopulateLocalMenu(Shape, localMenuShape, localMenuShape, menuItems); + Services.WorkContext.Layout.LocalNavigation.Add(localMenuShape); return View(blog); } diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Orchard.Blogs.csproj b/src/Orchard.Web/Modules/Orchard.Blogs/Orchard.Blogs.csproj index 926e6b2bee2..09bdb4befe6 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Orchard.Blogs.csproj +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Orchard.Blogs.csproj @@ -96,6 +96,7 @@ + @@ -155,10 +156,13 @@ + + + diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/ResourceManifest.cs b/src/Orchard.Web/Modules/Orchard.Blogs/ResourceManifest.cs index 73cec544281..46b2ab3c115 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/ResourceManifest.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/ResourceManifest.cs @@ -4,10 +4,14 @@ namespace Orchard.Blogs { public class ResourceManifest : IResourceManifestProvider { public void BuildManifests(ResourceManifestBuilder builder) { var manifest = builder.Add(); - manifest.DefineStyle("BlogsAdmin").SetUrl("orchard-blogs-admin.css"); - manifest.DefineStyle("BlogsArchives").SetUrl("orchard-blogs-archives.css"); + manifest.DefineStyle("BlogsAdmin") + .SetUrl("orchard-blogs-admin.min.css", "orchard-blogs-admin.css"); + manifest.DefineStyle("BlogsArchives") + .SetUrl("orchard-blogs-archives.min.css", "orchard-blogs-archives.css"); - manifest.DefineScript("BlogsArchives").SetUrl("orchard-blogs-archives.js").SetDependencies("jQuery"); + manifest.DefineScript("BlogsArchives") + .SetUrl("orchard-blogs-archives.min.js", "orchard-blogs-archives.js") + .SetDependencies("jQuery"); } } } diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Scripts/orchard-blogs-archives.min.js b/src/Orchard.Web/Modules/Orchard.Blogs/Scripts/orchard-blogs-archives.min.js new file mode 100644 index 00000000000..f88f74ff1bf --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Scripts/orchard-blogs-archives.min.js @@ -0,0 +1 @@ +!function($){$((function(){$(".archives ul.years li.previous").each((function(){$(this).click((function(ev){ev&&!$(ev.target).not("a").size()||($(this).toggleClass("open"),$(this).find("h4>span").toggle(),$(this).children("ul").toggle())}))}))}))}(jQuery); \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Styles/orchard-blogs-admin.min.css b/src/Orchard.Web/Modules/Orchard.Blogs/Styles/orchard-blogs-admin.min.css new file mode 100644 index 00000000000..d88e1f4c5ac --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Styles/orchard-blogs-admin.min.css @@ -0,0 +1 @@ +#main .blog-description p{margin-bottom:1em} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Styles/orchard-blogs-archives.min.css b/src/Orchard.Web/Modules/Orchard.Blogs/Styles/orchard-blogs-archives.min.css new file mode 100644 index 00000000000..3eb325a8c1f --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Styles/orchard-blogs-archives.min.css @@ -0,0 +1 @@ +.archives h3{margin-bottom:0}.archives ul{margin:0;padding:0}.archives ul .archives li{list-style-type:none}.archives ul.years li{list-style-type:none;margin:.6em 0 0}.archives ul.archiveMonthList li{margin:.2em 0}.archives ul.archiveMonthList li.first{margin-top:0}.archives ul.archiveMonthList li.last{margin-bottom:0}.archives ul.years li.previous h4 span{display:none}html.dyn .archives ul.years li.previous h4 span{display:inline}html.dyn .archives ul.years li h4,html.dyn .archives ul.years li ul{margin:.2em .2ex}html.dyn .archives ul.years li.previous h4:before{content:"⇓ "}html.dyn .archives ul.years li.previous{cursor:pointer;padding:.1em .2ex .2em 2ex;margin:0 -2ex}html.dyn .archives ul.years li.previous.hover{background-position:0 6px}html.dyn .archives ul.years li.previous.open h4:before{content:"⇑ "}html.dyn .archives ul.years li.previous.open.hover{background-position:0 6px}html.dyn .archives ul.years li.previous ul{display:none;margin-left:2ex} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Views/BlogAdmin/Item.cshtml b/src/Orchard.Web/Modules/Orchard.Blogs/Views/BlogAdmin/Item.cshtml index 6534c6b2f79..76581b42c5f 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Views/BlogAdmin/Item.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Views/BlogAdmin/Item.cshtml @@ -1,5 +1,5 @@ @{ Layout.Title = T("Manage Blog").ToString(); } - @* Model is a Shape, calling Display() so that it is rendered using the most specific template for its Shape type *@ - @Display(Model) +@* Model is a Shape, calling Display() so that it is rendered using the most specific template for its Shape type *@ +@Display(Model) diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Web.config b/src/Orchard.Web/Modules/Orchard.Blogs/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Orchard.Caching.csproj b/src/Orchard.Web/Modules/Orchard.Caching/Orchard.Caching.csproj index cfcb66853bf..e5287c07311 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Orchard.Caching.csproj +++ b/src/Orchard.Web/Modules/Orchard.Caching/Orchard.Caching.csproj @@ -71,7 +71,6 @@ ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - True diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Web.config b/src/Orchard.Web/Modules/Orchard.Caching/Web.config index 580c0124cfc..1fc8f61a052 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Caching/Web.config @@ -33,24 +33,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -63,6 +63,6 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.CodeGeneration/Web.config b/src/Orchard.Web/Modules/Orchard.CodeGeneration/Web.config index 580c0124cfc..1fc8f61a052 100644 --- a/src/Orchard.Web/Modules/Orchard.CodeGeneration/Web.config +++ b/src/Orchard.Web/Modules/Orchard.CodeGeneration/Web.config @@ -33,24 +33,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -63,6 +63,6 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Web.config b/src/Orchard.Web/Modules/Orchard.Comments/Web.config index 796fce354ee..dd5ba37c1c8 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Comments/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Conditions/Web.config b/src/Orchard.Web/Modules/Orchard.Conditions/Web.config index 2b84b41a8f6..b4b1cf0de0f 100644 --- a/src/Orchard.Web/Modules/Orchard.Conditions/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Conditions/Web.config @@ -36,24 +36,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -66,6 +66,6 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.ContentPermissions/Web.config b/src/Orchard.Web/Modules/Orchard.ContentPermissions/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPermissions/Web.config +++ b/src/Orchard.Web/Modules/Orchard.ContentPermissions/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Drivers/ContentPickerFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.ContentPicker/Drivers/ContentPickerFieldDriver.cs index 50ac2d5d771..85609bef513 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Drivers/ContentPickerFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Drivers/ContentPickerFieldDriver.cs @@ -89,8 +89,7 @@ protected override DriverResult Editor(ContentPart part, Fields.ContentPickerFie if (String.IsNullOrEmpty(model.SelectedIds)) { field.Ids = new int[0]; - } - else { + } else { field.Ids = model.SelectedIds.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray(); } @@ -102,14 +101,18 @@ protected override DriverResult Editor(ContentPart part, Fields.ContentPickerFie } protected override void Importing(ContentPart part, Fields.ContentPickerField field, ImportContentContext context) { - var contentItemIds = context.Attribute(field.FieldDefinition.Name + "." + field.Name, "ContentItems"); - if (contentItemIds != null) { - field.Ids = contentItemIds.Split(',') - .Select(context.GetItemFromSession) - .Select(contentItem => contentItem.Id).ToArray(); - } - else { - field.Ids = new int[0]; + // If nothing about the field is inside the context, field is not modified. + // For this reason, check if the current element is inside the ImportContentContext. + var element = context.Data.Element(field.FieldDefinition.Name + "." + field.Name); + if (element != null) { + var contentItemIds = context.Attribute(field.FieldDefinition.Name + "." + field.Name, "ContentItems"); + if (contentItemIds != null) { + field.Ids = contentItemIds.Split(',') + .Select(context.GetItemFromSession) + .Select(contentItem => contentItem.Id).ToArray(); + } else { + field.Ids = new int[0]; + } } } diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Web.config b/src/Orchard.Web/Modules/Orchard.ContentPicker/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Web.config +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/packages.config b/src/Orchard.Web/Modules/Orchard.ContentPicker/packages.config index b536bbfa970..571aa7defed 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/packages.config +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/packages.config @@ -10,4 +10,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/EditField.cshtml b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/EditField.cshtml index feec8617963..c259852d74c 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/EditField.cshtml +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/EditField.cshtml @@ -12,13 +12,14 @@ @using (Html.BeginFormAntiForgeryPost()) { @Html.ValidationSummary() -
- - @Html.TextBoxFor(m => m.DisplayName, new {@class = "text medium", autofocus = "autofocus"}) - @T("Name of the field as it will be displayed in screens.") - - @Html.HiddenFor(m => m.Name) -
+
+ + @Html.TextBoxFor(m => m.DisplayName, new { @class = "text medium", autofocus = "autofocus" }) + @T("Name of the field as it will be displayed in screens.") + @T("Content Field Id: {0}", Model.Name) + + @Html.HiddenFor(m => m.Name) +
@if (!String.IsNullOrWhiteSpace(returnUrl) && Request.IsLocalUrl(returnUrl)) { diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/DisplayTemplates/EditTypeViewModel.cshtml b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/DisplayTemplates/EditTypeViewModel.cshtml index e3048f9992c..8c636ce37da 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/DisplayTemplates/EditTypeViewModel.cshtml +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/DisplayTemplates/EditTypeViewModel.cshtml @@ -11,6 +11,7 @@

@Model.DisplayName

@if (!string.IsNullOrWhiteSpace(stereotype)) { - @stereotype } + @if (!Model.DisplayName.Equals(Model.Name, StringComparison.OrdinalIgnoreCase)) { @T("Content Type name: {0}", Model.Name) } @if (settings.Creatable) {

@Html.ActionLink(T("Create New {0}", Html.Raw(Model.DisplayName)).Text, "Create", new {area = "Contents", id = Model.Name})

diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Web.config b/src/Orchard.Web/Modules/Orchard.ContentTypes/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Web.config +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.CustomForms/Web.config b/src/Orchard.Web/Modules/Orchard.CustomForms/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.CustomForms/Web.config +++ b/src/Orchard.Web/Modules/Orchard.CustomForms/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Dashboards/Web.config b/src/Orchard.Web/Modules/Orchard.Dashboards/Web.config index 8d49534ba2d..bec1fbda95b 100644 --- a/src/Orchard.Web/Modules/Orchard.Dashboards/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Dashboards/Web.config @@ -40,24 +40,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -70,8 +70,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.DesignerTools/Views/ShapeTracingWrapper.cshtml b/src/Orchard.Web/Modules/Orchard.DesignerTools/Views/ShapeTracingWrapper.cshtml index 4d189d9f4af..7585c312a43 100644 --- a/src/Orchard.Web/Modules/Orchard.DesignerTools/Views/ShapeTracingWrapper.cshtml +++ b/src/Orchard.Web/Modules/Orchard.DesignerTools/Views/ShapeTracingWrapper.cshtml @@ -17,17 +17,17 @@ } // Code Mirror - Script.Include("CodeMirror/codemirror.js"); + Script.Include("CodeMirror/codemirror.js").AtHead(); Style.Include("CodeMirror/codemirror.css"); - Script.Include("CodeMirror/razor.js"); + Script.Include("CodeMirror/razor.js").AtHead(); Style.Include("CodeMirror/razor.css"); - Script.Include("CodeMirror/javascript.js"); - Style.Include("CodeMirror/javascript.css"); - Script.Include("CodeMirror/css.js"); + Script.Include("CodeMirror/javascript.js").AtHead(); + Style.Include("CodeMirror/javascript.css").AtHead(); + Script.Include("CodeMirror/css.js").AtHead(); Style.Include("CodeMirror/css.css"); - Script.Include("CodeMirror/htmlmixed.js"); + Script.Include("CodeMirror/htmlmixed.js").AtHead(); - Script.Include("jquery.tmpl.min.js"); + Script.Include("jquery.tmpl.min.js").AtHead(); } @Display(Model.Metadata.ChildContent) diff --git a/src/Orchard.Web/Modules/Orchard.DesignerTools/Web.config b/src/Orchard.Web/Modules/Orchard.DesignerTools/Web.config index 23f41b31ee5..0413f9b6046 100644 --- a/src/Orchard.Web/Modules/Orchard.DesignerTools/Web.config +++ b/src/Orchard.Web/Modules/Orchard.DesignerTools/Web.config @@ -40,24 +40,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -70,8 +70,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Orchard.DynamicForms.csproj b/src/Orchard.Web/Modules/Orchard.DynamicForms/Orchard.DynamicForms.csproj index 8c7237510eb..59eb1c80ca0 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Orchard.DynamicForms.csproj +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Orchard.DynamicForms.csproj @@ -610,4 +610,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Web.config b/src/Orchard.Web/Modules/Orchard.DynamicForms/Web.config index c3ee86a72ec..8db95a03b33 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Web.config +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Web.config @@ -42,24 +42,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -72,8 +72,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/packages.config b/src/Orchard.Web/Modules/Orchard.DynamicForms/packages.config index 093ef9918c0..a978eee29f5 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/packages.config +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/packages.config @@ -7,4 +7,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Email/Orchard.Email.csproj b/src/Orchard.Web/Modules/Orchard.Email/Orchard.Email.csproj index 2206c0f1bc4..3e07097e36c 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Orchard.Email.csproj +++ b/src/Orchard.Web/Modules/Orchard.Email/Orchard.Email.csproj @@ -219,4 +219,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Email/Web.config b/src/Orchard.Web/Modules/Orchard.Email/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Email/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Email/packages.config b/src/Orchard.Web/Modules/Orchard.Email/packages.config index 2ae22b193cd..51c3aaef7f0 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Email/packages.config @@ -6,4 +6,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/BooleanFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/BooleanFieldDriver.cs index 4d55be49a49..6d07a6ad045 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/BooleanFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/BooleanFieldDriver.cs @@ -71,7 +71,7 @@ protected override void Cloning(ContentPart part, BooleanField originalField, Bo protected override void Describe(DescribeMembersContext context) { context - .Member(null, typeof(Boolean), T("Value"), T("The boolean value of the field.")) + .Member(null, typeof(Boolean?), T("Value"), T("The boolean value of the field.")) .Enumerate(() => field => new [] { field.Value }) ; } diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/NumericFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/NumericFieldDriver.cs index 85c7cff58e4..d7394be5412 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/NumericFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/NumericFieldDriver.cs @@ -102,7 +102,13 @@ protected override DriverResult Editor(ContentPart part, NumericField field, IUp } protected override void Importing(ContentPart part, NumericField field, ImportContentContext context) { - context.ImportAttribute(field.FieldDefinition.Name + "." + field.Name, "Value", v => field.Value = decimal.Parse(v, CultureInfo.InvariantCulture), () => field.Value = (decimal?)null); + Action empty = (() => field.Value = (decimal?)null); + var element = context.Data.Element(field.FieldDefinition.Name + "." + field.Name); + // If element is not in the ImportContentContext, field must not be reset. + if (element == null) { + empty = () => { }; + } + context.ImportAttribute(field.FieldDefinition.Name + "." + field.Name, "Value", v => field.Value = decimal.Parse(v, CultureInfo.InvariantCulture), empty); } protected override void Exporting(ContentPart part, NumericField field, ExportContentContext context) { diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Views/EditorTemplates/Fields/Boolean.Edit.cshtml b/src/Orchard.Web/Modules/Orchard.Fields/Views/EditorTemplates/Fields/Boolean.Edit.cshtml index f2b8ca3fea3..f0b1188b9eb 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Views/EditorTemplates/Fields/Boolean.Edit.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Fields/Views/EditorTemplates/Fields/Boolean.Edit.cshtml @@ -13,17 +13,17 @@ case SelectionMode.Radiobutton: if (settings.Optional) {
- checked="checked" } /> - + checked="checked" } /> +
}
- checked="checked" } /> - + checked="checked" } /> +
- checked="checked" } /> - + checked="checked" } /> +
break; case SelectionMode.Dropdown: diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Web.config b/src/Orchard.Web/Modules/Orchard.Fields/Web.config index 2ba6f951e1c..25cb4e3650f 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Fields/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Forms/Orchard.Forms.csproj b/src/Orchard.Web/Modules/Orchard.Forms/Orchard.Forms.csproj index d210e6c6831..02018c06aba 100644 --- a/src/Orchard.Web/Modules/Orchard.Forms/Orchard.Forms.csproj +++ b/src/Orchard.Web/Modules/Orchard.Forms/Orchard.Forms.csproj @@ -175,4 +175,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Forms/Web.config b/src/Orchard.Web/Modules/Orchard.Forms/Web.config index e135f5f023d..73a184e136a 100644 --- a/src/Orchard.Web/Modules/Orchard.Forms/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Forms/Web.config @@ -35,24 +35,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -65,6 +65,6 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Forms/packages.config b/src/Orchard.Web/Modules/Orchard.Forms/packages.config index d8a6250222a..f89bcaa42ad 100644 --- a/src/Orchard.Web/Modules/Orchard.Forms/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Forms/packages.config @@ -5,4 +5,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.ImageEditor/Web.config b/src/Orchard.Web/Modules/Orchard.ImageEditor/Web.config index d9a2321ac22..efa898a69bc 100644 --- a/src/Orchard.Web/Modules/Orchard.ImageEditor/Web.config +++ b/src/Orchard.Web/Modules/Orchard.ImageEditor/Web.config @@ -40,24 +40,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -70,8 +70,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.ImportExport/Web.config b/src/Orchard.Web/Modules/Orchard.ImportExport/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.ImportExport/Web.config +++ b/src/Orchard.Web/Modules/Orchard.ImportExport/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.ImportExport/packages.config b/src/Orchard.Web/Modules/Orchard.ImportExport/packages.config index a933401b4bc..18a3177cd52 100644 --- a/src/Orchard.Web/Modules/Orchard.ImportExport/packages.config +++ b/src/Orchard.Web/Modules/Orchard.ImportExport/packages.config @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Web.config b/src/Orchard.Web/Modules/Orchard.Indexing/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.JobsQueue/Orchard.JobsQueue.csproj b/src/Orchard.Web/Modules/Orchard.JobsQueue/Orchard.JobsQueue.csproj index af5b259b92b..58f4b43a10d 100644 --- a/src/Orchard.Web/Modules/Orchard.JobsQueue/Orchard.JobsQueue.csproj +++ b/src/Orchard.Web/Modules/Orchard.JobsQueue/Orchard.JobsQueue.csproj @@ -204,4 +204,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.JobsQueue/Tests/Orchard.Messaging.Tests.csproj b/src/Orchard.Web/Modules/Orchard.JobsQueue/Tests/Orchard.Messaging.Tests.csproj index ae415be7669..6ea952ce296 100644 --- a/src/Orchard.Web/Modules/Orchard.JobsQueue/Tests/Orchard.Messaging.Tests.csproj +++ b/src/Orchard.Web/Modules/Orchard.JobsQueue/Tests/Orchard.Messaging.Tests.csproj @@ -44,9 +44,8 @@ False ..\..\..\..\..\lib\moq\Moq.dll - - False - ..\..\..\..\..\lib\newtonsoft.json\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll ..\..\..\..\..\lib\nunit\nunit.framework.dll diff --git a/src/Orchard.Web/Modules/Orchard.JobsQueue/Web.config b/src/Orchard.Web/Modules/Orchard.JobsQueue/Web.config index 854be8b67fa..0df49e40c1c 100644 --- a/src/Orchard.Web/Modules/Orchard.JobsQueue/Web.config +++ b/src/Orchard.Web/Modules/Orchard.JobsQueue/Web.config @@ -29,6 +29,7 @@ + @@ -39,24 +40,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +70,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.JobsQueue/packages.config b/src/Orchard.Web/Modules/Orchard.JobsQueue/packages.config index 2ae22b193cd..51c3aaef7f0 100644 --- a/src/Orchard.Web/Modules/Orchard.JobsQueue/packages.config +++ b/src/Orchard.Web/Modules/Orchard.JobsQueue/packages.config @@ -6,4 +6,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/HtmlElementDriver.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/HtmlElementDriver.cs index 09d877c5be3..eb62d7616a8 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/HtmlElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/HtmlElementDriver.cs @@ -15,7 +15,8 @@ public HtmlElementDriver(IElementFilterProcessor processor) { protected override EditorResult OnBuildEditor(Html element, ElementEditorContext context) { var viewModel = new HtmlEditorViewModel { - Text = element.Content + Text = element.Content, + Part = ((dynamic)context.Content.ContentItem).LayoutPart }; var editor = context.ShapeFactory.EditorTemplate(TemplateName: "Elements.Html", Model: viewModel); diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Orchard.Layouts.csproj b/src/Orchard.Web/Modules/Orchard.Layouts/Orchard.Layouts.csproj index e6f944b87c9..25e4e45eaea 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Orchard.Layouts.csproj +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Orchard.Layouts.csproj @@ -69,7 +69,6 @@ 3.5 - ..\..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.7\lib\net45\System.Net.Http.Formatting.dll diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/ViewModels/HtmlEditorViewModel.cs b/src/Orchard.Web/Modules/Orchard.Layouts/ViewModels/HtmlEditorViewModel.cs index dc64dab098e..ab84b14652f 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/ViewModels/HtmlEditorViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/ViewModels/HtmlEditorViewModel.cs @@ -1,5 +1,8 @@ -namespace Orchard.Layouts.ViewModels { +using Orchard.ContentManagement; + +namespace Orchard.Layouts.ViewModels { public class HtmlEditorViewModel { public string Text { get; set; } + public ContentPart Part { get; set; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Views/EditorTemplates/Elements.Html.cshtml b/src/Orchard.Web/Modules/Orchard.Layouts/Views/EditorTemplates/Elements.Html.cshtml index 1df31b7320c..32bbe1ee98f 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Views/EditorTemplates/Elements.Html.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Views/EditorTemplates/Elements.Html.cshtml @@ -1,5 +1,5 @@ @model Orchard.Layouts.ViewModels.HtmlEditorViewModel
@Html.LabelFor(m => m.Text, T("HTML")) - @Display.Body_Editor(EditorFlavor: "html", Text: Model.Text, AutoFocus: true) + @Display.Body_Editor(EditorFlavor: "html", Text: Model.Text, AutoFocus: true, Part: Model.Part)
\ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Web.config b/src/Orchard.Web/Modules/Orchard.Layouts/Web.config index fdaaff808e1..3fc956dcab7 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Web.config @@ -40,24 +40,36 @@ - - - - + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -70,8 +82,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Lists/Web.config b/src/Orchard.Web/Modules/Orchard.Lists/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.Lists/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Lists/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Localization/Handlers/LocalizationPartHandler.cs b/src/Orchard.Web/Modules/Orchard.Localization/Handlers/LocalizationPartHandler.cs index 67293758bd1..138287afe71 100644 --- a/src/Orchard.Web/Modules/Orchard.Localization/Handlers/LocalizationPartHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Localization/Handlers/LocalizationPartHandler.cs @@ -31,22 +31,26 @@ public LocalizationPartHandler(IRepository localizedRepo protected static void PropertySetHandlers(ActivatedContentContext context, LocalizationPart localizationPart) { localizationPart.CultureField.Setter(cultureRecord => { - localizationPart.Record.CultureId = cultureRecord != null ? cultureRecord.Id : 0; + localizationPart.Store(r => r.CultureId, + cultureRecord != null ? cultureRecord.Id : 0); return cultureRecord; }); - + localizationPart.MasterContentItemField.Setter(masterContentItem => { - localizationPart.Record.MasterContentItemId = masterContentItem.ContentItem.Id; + localizationPart.Store(r => r.MasterContentItemId, + masterContentItem.ContentItem.Id); return masterContentItem; - }); + }); } protected void LazyLoadHandlers(LocalizationPart localizationPart) { - localizationPart.CultureField.Loader(() => - _cultureManager.GetCultureById(localizationPart.Record.CultureId)); + localizationPart.CultureField.Loader(() => + _cultureManager.GetCultureById( + localizationPart.Retrieve(r => r.CultureId))); localizationPart.MasterContentItemField.Loader(() => - _contentManager.Get(localizationPart.Record.MasterContentItemId, VersionOptions.AllVersions)); + _contentManager.Get( + localizationPart.Retrieve(r => r.MasterContentItemId), VersionOptions.AllVersions)); } } } diff --git a/src/Orchard.Web/Modules/Orchard.Localization/Web.config b/src/Orchard.Web/Modules/Orchard.Localization/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.Localization/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Localization/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Media/Web.config b/src/Orchard.Web/Modules/Orchard.Media/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.Media/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Media/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaLibraryPickerFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaLibraryPickerFieldDriver.cs index 34df7feee12..998ede7932c 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaLibraryPickerFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaLibraryPickerFieldDriver.cs @@ -73,14 +73,20 @@ protected override DriverResult Editor(ContentPart part, Fields.MediaLibraryPick } protected override void Importing(ContentPart part, Fields.MediaLibraryPickerField field, ImportContentContext context) { - var contentItemIds = context.Attribute(field.FieldDefinition.Name + "." + field.Name, "ContentItems"); - if (contentItemIds != null) { - field.Ids = contentItemIds.Split(',') - .Select(context.GetItemFromSession) - .Select(contentItem => contentItem.Id).ToArray(); - } - else { - field.Ids = new int[0]; + // If nothing about the field is inside the context, field is not modified. + // For this reason, check if the current element is inside the ImportContentContext. + var element = context.Data.Element(field.FieldDefinition.Name + "." + field.Name); + if (element != null) { + var contentItemIds = context.Attribute(field.FieldDefinition.Name + "." + field.Name, "ContentItems"); + if (contentItemIds != null) { + if (!string.IsNullOrWhiteSpace(contentItemIds)) { + field.Ids = contentItemIds.Split(',') + .Select(context.GetItemFromSession) + .Select(contentItem => contentItem.Id).ToArray(); + } + } else { + field.Ids = new int[0]; + } } } diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Models/MediaLibrarySettingsPart.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Models/MediaLibrarySettingsPart.cs index b061059bc58..4d549cec94a 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Models/MediaLibrarySettingsPart.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Models/MediaLibrarySettingsPart.cs @@ -13,6 +13,11 @@ public string UploadAllowedFileTypeWhitelist { set { this.Store(x => x.UploadAllowedFileTypeWhitelist, value); } } + public int LimitConcurrentUploads { + get { return this.Retrieve(x => x.LimitConcurrentUploads); } + set { this.Store(x => x.LimitConcurrentUploads, value); } + } + public bool IsFileAllowed(string filename) { var allowedExtensions = (UploadAllowedFileTypeWhitelist ?? "") diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Orchard.MediaLibrary.csproj b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Orchard.MediaLibrary.csproj index 13570d24749..1a16a351baa 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Orchard.MediaLibrary.csproj +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Orchard.MediaLibrary.csproj @@ -486,4 +486,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Styles/media-library-picker-admin.css b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Styles/media-library-picker-admin.css index 4824a1f0ac7..4aef7a4d6a1 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Styles/media-library-picker-admin.css +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Styles/media-library-picker-admin.css @@ -58,6 +58,10 @@ height: 40px; overflow: hidden; } +.thumbnail .overlay { + height: 40px; + overflow: hidden; +} .overlay h3 { padding-right:5px; diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/ClientStorage/Index.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/ClientStorage/Index.cshtml index cf1d393dbc7..f3df7de41e1 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/ClientStorage/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/ClientStorage/Index.cshtml @@ -1,4 +1,7 @@ -@model Orchard.MediaLibrary.ViewModels.ImportMediaViewModel +@using Orchard.MediaLibrary.Models; +@using Orchard.ContentManagement; + +@model Orchard.MediaLibrary.ViewModels.ImportMediaViewModel @@ -12,6 +15,8 @@ Script.Require("jQueryFileUpload").AtFoot(); Script.Require("Knockout").AtFoot(); + + var settings = WorkContext.CurrentSite.As(); } @Display.Metas() @@ -23,7 +28,7 @@
@T("Click here, Drop files or Paste images")
- multiple="multiple" } > + multiple="multiple" } />
  • @@ -36,9 +41,9 @@
- + @using (Script.Foot()) { - + } - + @Display.FootScripts() \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/EditorTemplates/Parts/MediaLibrary.MediaLibrarySettings.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/EditorTemplates/Parts/MediaLibrary.MediaLibrarySettings.cshtml index 82fdaf19cfa..dc07b9b1c2e 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/EditorTemplates/Parts/MediaLibrary.MediaLibrarySettings.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/EditorTemplates/Parts/MediaLibrary.MediaLibrarySettings.cshtml @@ -6,5 +6,8 @@ @Html.TextBoxFor(m => m.UploadAllowedFileTypeWhitelist, new { @class = "text large"}) @T("A comma separated list of file extensions, e.g., \".jpg, .avi, .txt\". Leave empty to accept any file types.") + + @Html.TextBoxFor(m => m.LimitConcurrentUploads, new { @class = "text medium"}) + @T("To limit the number of concurrent uploads, set this value to an integer greater than 0")
\ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/MediaLibraryPicker.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/MediaLibraryPicker.cshtml index 165dd7179f8..9c4fa05c312 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/MediaLibraryPicker.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/MediaLibraryPicker.cshtml @@ -1,6 +1,6 @@ @using Orchard.ContentManagement -@using Orchard.Localization.Models; -@using Orchard.Utility.Extensions; +@using Orchard.Localization.Models +@using Orchard.Utility.Extensions @{ Style.Include("media-library-picker-admin.css"); diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Web.config b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Web.config index 23f41b31ee5..0413f9b6046 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Web.config +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Web.config @@ -40,24 +40,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -70,8 +70,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/packages.config b/src/Orchard.Web/Modules/Orchard.MediaLibrary/packages.config index 2ae22b193cd..51c3aaef7f0 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/packages.config +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/packages.config @@ -6,4 +6,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.MediaPicker/Web.config b/src/Orchard.Web/Modules/Orchard.MediaPicker/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaPicker/Web.config +++ b/src/Orchard.Web/Modules/Orchard.MediaPicker/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProfileManager.cs b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProfileManager.cs index a5cd621619d..dc6620035af 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProfileManager.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProfileManager.cs @@ -171,6 +171,8 @@ public string GetImageProfileUrl(string path, string profileName, ContentItem co } } } + // the storage provider may have altered the filepath + filterContext.FilePath = newFile.GetPath(); } } catch(Exception e) { diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Web.config b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Web.config +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.MessageBus/Orchard.MessageBus.csproj b/src/Orchard.Web/Modules/Orchard.MessageBus/Orchard.MessageBus.csproj index 02662a4ddee..d54d98cdc37 100644 --- a/src/Orchard.Web/Modules/Orchard.MessageBus/Orchard.MessageBus.csproj +++ b/src/Orchard.Web/Modules/Orchard.MessageBus/Orchard.MessageBus.csproj @@ -186,4 +186,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.MessageBus/Web.config b/src/Orchard.Web/Modules/Orchard.MessageBus/Web.config index 580c0124cfc..1fc8f61a052 100644 --- a/src/Orchard.Web/Modules/Orchard.MessageBus/Web.config +++ b/src/Orchard.Web/Modules/Orchard.MessageBus/Web.config @@ -33,24 +33,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -63,6 +63,6 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.MessageBus/packages.config b/src/Orchard.Web/Modules/Orchard.MessageBus/packages.config index 8fbb396f466..249ae771231 100644 --- a/src/Orchard.Web/Modules/Orchard.MessageBus/packages.config +++ b/src/Orchard.Web/Modules/Orchard.MessageBus/packages.config @@ -9,4 +9,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Migrations/Web.config b/src/Orchard.Web/Modules/Orchard.Migrations/Web.config index 580c0124cfc..1fc8f61a052 100644 --- a/src/Orchard.Web/Modules/Orchard.Migrations/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Migrations/Web.config @@ -33,24 +33,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -63,6 +63,6 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Modules/Web.config b/src/Orchard.Web/Modules/Orchard.Modules/Web.config index ec624b0db27..ae6866773ad 100644 --- a/src/Orchard.Web/Modules/Orchard.Modules/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Modules/Web.config @@ -38,24 +38,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -68,8 +68,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Web.config b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Web.config index ec624b0db27..ae6866773ad 100644 --- a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Web.config +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Web.config @@ -38,24 +38,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -68,8 +68,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/packages.config b/src/Orchard.Web/Modules/Orchard.MultiTenancy/packages.config index a933401b4bc..18a3177cd52 100644 --- a/src/Orchard.Web/Modules/Orchard.MultiTenancy/packages.config +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/packages.config @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs index b37825b3cca..30c3183eef9 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs @@ -192,7 +192,7 @@ public void OnResultExecuted(ResultExecutedContext filterContext) { Logger.Debug("Item '{0}' was rendered.", _cacheKey); - + if (!ResponseIsCacheable(filterContext)) { filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache); filterContext.HttpContext.Response.Cache.SetNoStore(); @@ -395,6 +395,9 @@ protected virtual IDictionary GetCacheKeyParameters(ActionExecut // Vary by theme. result.Add("theme", _workContext.CurrentTheme.Id.ToLowerInvariant()); + // Vary for ajax vs "normal" calls + result.Add("isajax", filterContext.HttpContext.Request.IsAjaxRequest().ToString()); + // Vary by configured query string parameters. var queryString = filterContext.RequestContext.HttpContext.Request.QueryString; foreach (var key in queryString.AllKeys) { @@ -415,7 +418,7 @@ protected virtual IDictionary GetCacheKeyParameters(ActionExecut // Vary by configured request headers. var requestHeaders = filterContext.RequestContext.HttpContext.Request.Headers; foreach (var varyByRequestHeader in CacheSettings.VaryByRequestHeaders) { - if (requestHeaders[varyByRequestHeader]!=null) + if (requestHeaders[varyByRequestHeader] != null) result["HEADER:" + varyByRequestHeader] = requestHeaders[varyByRequestHeader]; } @@ -537,7 +540,7 @@ private void ServeCachedItem(ActionExecutingContext filterContext, CacheItem cac response.AddHeader("X-Cached-On", cacheItem.CachedOnUtc.ToString("r")); response.AddHeader("X-Cached-Until", cacheItem.ValidUntilUtc.ToString("r")); } - + // Shorcut action execution. filterContext.Result = new FileContentResult( ReplaceBeaconTagWithFreshRequestVerificationToken(cacheItem.Output, response.ContentEncoding), // replace the beacon created by the ReplaceRequestVerificationTokenWithBeacon method witha fresh new one @@ -555,7 +558,7 @@ private void ServeCachedItem(ActionExecutingContext filterContext, CacheItem cac if (response.Headers.Get("ETag") == null) { response.Headers["ETag"] = newEtag; itemETag = newEtag; - } + } } } else { @@ -806,7 +809,7 @@ protected virtual void Dispose(bool disposing) { // Ensure locks are released even after an unexpected exception Dispose(false); } - + } public class ViewDataContainer : IViewDataContainer { diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Web.config b/src/Orchard.Web/Modules/Orchard.OutputCache/Web.config index 4a5287ab161..a21b694d2a6 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Web.config +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Web.config b/src/Orchard.Web/Modules/Orchard.Packaging/Web.config index 868138d6379..add97b3e511 100644 --- a/src/Orchard.Web/Modules/Orchard.Packaging/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Packaging/Web.config @@ -40,24 +40,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -70,8 +70,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Pages/Web.config b/src/Orchard.Web/Modules/Orchard.Pages/Web.config index 16e4b160359..45d70d0cf39 100644 --- a/src/Orchard.Web/Modules/Orchard.Pages/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Pages/Web.config @@ -35,24 +35,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - + + + diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Migrations.cs b/src/Orchard.Web/Modules/Orchard.Projections/Migrations.cs index fb0b4d90a2d..cbf33106f9a 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Migrations.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Migrations.cs @@ -1,7 +1,6 @@ using System; using System.Data; using System.Linq; -using Orchard.ContentManagement; using Orchard.ContentManagement.MetaData; using Orchard.Core.Common.Models; using Orchard.Core.Contents.Extensions; @@ -16,12 +15,20 @@ public class Migrations : DataMigrationImpl { private readonly IRepository _memberBindingRepository; private readonly IRepository _layoutRepository; private readonly IRepository _propertyRecordRepository; - + + /// + /// When upgrading from "1.10.x" branch code committed after 1.10.3 to "dev" branch code or 1.11, merge + /// conflicts between "1.10.x" and "dev" caused by running the same migration steps in a different order need to + /// be resolved by instructing this migration to decide which steps need to be executed. If you're upgrading + /// under these conditions and your pre-upgrade migration version is 6, use HostComponents.config to override + /// this property to true. + /// + public bool IsUpgradingFromOrchard_1_10_x_Version_6 { get; set; } + public Migrations( IRepository memberBindingRepository, IRepository layoutRepository, IRepository propertyRecordRepository) { - _memberBindingRepository = memberBindingRepository; _layoutRepository = layoutRepository; _propertyRecordRepository = propertyRecordRepository; @@ -40,6 +47,7 @@ public int Create() { .Column("Id", c => c.PrimaryKey().Identity()) .Column("PropertyName") .Column("Value", c => c.WithLength(4000)) + .Column("LatestValue", c => c.WithLength(4000)) .Column("FieldIndexPartRecord_Id") ); @@ -48,6 +56,7 @@ public int Create() { .Column("Id", c => c.PrimaryKey().Identity()) .Column("PropertyName") .Column("Value") + .Column("LatestValue") .Column("FieldIndexPartRecord_Id") ); @@ -56,6 +65,7 @@ public int Create() { .Column("Id", c => c.PrimaryKey().Identity()) .Column("PropertyName") .Column("Value") + .Column("LatestValue") .Column("FieldIndexPartRecord_Id") ); @@ -64,9 +74,28 @@ public int Create() { .Column("Id", c => c.PrimaryKey().Identity()) .Column("PropertyName") .Column("Value") + .Column("LatestValue") .Column("FieldIndexPartRecord_Id") ); + //Adds indexes for better performances in queries + SchemaBuilder.AlterTable("StringFieldIndexRecord", table => { + table.CreateIndex("IDX_Orchard_Projections_PropertyName", "PropertyName"); + table.CreateIndex("IDX_Orchard_Projections_StringFieldIndexRecord", "FieldIndexPartRecord_Id"); + }); + SchemaBuilder.AlterTable("IntegerFieldIndexRecord", table => { + table.CreateIndex("IDX_Orchard_Projections_PropertyName", "PropertyName"); + table.CreateIndex("IDX_Orchard_Projections_IntegerFieldIndexRecord", "FieldIndexPartRecord_Id"); + }); + SchemaBuilder.AlterTable("DoubleFieldIndexRecord", table => { + table.CreateIndex("IDX_Orchard_Projections_PropertyName", "PropertyName"); + table.CreateIndex("IDX_Orchard_Projections_DoubleFieldIndexRecord", "FieldIndexPartRecord_Id"); + }); + SchemaBuilder.AlterTable("DecimalFieldIndexRecord", table => { + table.CreateIndex("IDX_Orchard_Projections_PropertyName", "PropertyName"); + table.CreateIndex("IDX_Orchard_Projections_DecimalFieldIndexRecords", "FieldIndexPartRecord_Id"); + }); + SchemaBuilder.CreateTable("FieldIndexPartRecord", table => table.ContentPartRecord()); // Query @@ -81,6 +110,7 @@ public int Create() { SchemaBuilder.CreateTable("QueryPartRecord", table => table .ContentPartRecord() + .Column("VersionScope", c => c.WithLength(15)) ); SchemaBuilder.CreateTable("FilterGroupRecord", @@ -119,6 +149,7 @@ public int Create() { .Column("Description", c => c.WithLength(255)) .Column("State", c => c.Unlimited()) .Column("DisplayType", c => c.WithLength(64)) + .Column("GUIdentifier", column => column.WithLength(68)) .Column("Display") .Column("QueryPartRecord_id") .Column("GroupProperty_id") @@ -154,6 +185,7 @@ public int Create() { .Column("HideEmpty") .Column("RewriteOutput") + .Column("RewriteOutputCondition", c => c.Unlimited()) .Column("RewriteText", c => c.Unlimited()) .Column("StripHtmlTags") .Column("TrimLength") @@ -252,19 +284,6 @@ public int Create() { Description = T("The text from the Body part").Text }); - SchemaBuilder.AlterTable("StringFieldIndexRecord", table => table - .CreateIndex("IDX_Orchard_Projections_StringFieldIndexRecord", "FieldIndexPartRecord_Id") - ); - SchemaBuilder.AlterTable("IntegerFieldIndexRecord", table => table - .CreateIndex("IDX_Orchard_Projections_IntegerFieldIndexRecord", "FieldIndexPartRecord_Id") - ); - SchemaBuilder.AlterTable("DoubleFieldIndexRecord", table => table - .CreateIndex("IDX_Orchard_Projections_DoubleFieldIndexRecord", "FieldIndexPartRecord_Id") - ); - SchemaBuilder.AlterTable("DecimalFieldIndexRecord", table => table - .CreateIndex("IDX_Orchard_Projections_DecimalFieldIndexRecords", "FieldIndexPartRecord_Id") - ); - SchemaBuilder.CreateTable("NavigationQueryPartRecord", table => table.ContentPartRecord() .Column("Items") @@ -283,7 +302,7 @@ public int Create() { .WithIdentity() ); - return 4; + return 7; } public int UpdateFrom1() { @@ -306,7 +325,7 @@ public int UpdateFrom1() { ContentDefinitionManager.AlterTypeDefinition("ProjectionPage", cfg => cfg.Listable()); - return 3; + return 2; } public int UpdateFrom2() { @@ -328,29 +347,34 @@ public int UpdateFrom3() { public int UpdateFrom4() { SchemaBuilder.AlterTable("StringFieldIndexRecord", table => table - .AddColumn("LatestValue", c => c.WithLength(4000))); + .AddColumn("LatestValue", c => c.WithLength(4000))); SchemaBuilder.AlterTable("IntegerFieldIndexRecord", table => table - .AddColumn("LatestValue")); + .AddColumn("LatestValue")); SchemaBuilder.AlterTable("DoubleFieldIndexRecord", table => table - .AddColumn("LatestValue")); + .AddColumn("LatestValue")); SchemaBuilder.AlterTable("DecimalFieldIndexRecord", table => table - .AddColumn("LatestValue")); + .AddColumn("LatestValue")); //Adds indexes for better performances in queries - SchemaBuilder.AlterTable("StringFieldIndexRecord", table => table.CreateIndex("IX_PropertyName", new string[] { "PropertyName" })); - SchemaBuilder.AlterTable("StringFieldIndexRecord", table => table.CreateIndex("IX_FieldIndexPartRecord_Id", new string[] { "FieldIndexPartRecord_Id" })); - - SchemaBuilder.AlterTable("IntegerFieldIndexRecord", table => table.CreateIndex("IX_PropertyName", new string[] { "PropertyName" })); - SchemaBuilder.AlterTable("IntegerFieldIndexRecord", table => table.CreateIndex("IX_FieldIndexPartRecord_Id", new string[] { "FieldIndexPartRecord_Id" })); - - SchemaBuilder.AlterTable("DoubleFieldIndexRecord", table => table.CreateIndex("IX_PropertyName", new string[] { "PropertyName" })); - SchemaBuilder.AlterTable("DoubleFieldIndexRecord", table => table.CreateIndex("IX_FieldIndexPartRecord_Id", new string[] { "FieldIndexPartRecord_Id" })); - - SchemaBuilder.AlterTable("DecimalFieldIndexRecord", table => table.CreateIndex("IX_PropertyName", new string[] { "PropertyName" })); - SchemaBuilder.AlterTable("DecimalFieldIndexRecord", table => table.CreateIndex("IX_FieldIndexPartRecord_Id", new string[] { "FieldIndexPartRecord_Id" })); + SchemaBuilder.AlterTable("StringFieldIndexRecord", table => { + table.CreateIndex("IDX_Orchard_Projections_PropertyName", "PropertyName"); + table.CreateIndex("IDX_Orchard_Projections_StringFieldIndexRecord", "FieldIndexPartRecord_Id"); + }); + SchemaBuilder.AlterTable("IntegerFieldIndexRecord", table => { + table.CreateIndex("IDX_Orchard_Projections_PropertyName", "PropertyName"); + table.CreateIndex("IDX_Orchard_Projections_IntegerFieldIndexRecord", "FieldIndexPartRecord_Id"); + }); + SchemaBuilder.AlterTable("DoubleFieldIndexRecord", table => { + table.CreateIndex("IDX_Orchard_Projections_PropertyName", "PropertyName"); + table.CreateIndex("IDX_Orchard_Projections_DoubleFieldIndexRecord", "FieldIndexPartRecord_Id"); + }); + SchemaBuilder.AlterTable("DecimalFieldIndexRecord", table => { + table.CreateIndex("IDX_Orchard_Projections_PropertyName", "PropertyName"); + table.CreateIndex("IDX_Orchard_Projections_DecimalFieldIndexRecords", "FieldIndexPartRecord_Id"); + }); SchemaBuilder.AlterTable("QueryPartRecord", table => table .AddColumn("VersionScope", c => c.WithLength(15))); @@ -358,32 +382,41 @@ public int UpdateFrom4() { return 5; } -#pragma warning disable CS0618 - // disable compiler warning regarding the fact that RewriteOutput is obsolete - // because this migration is handling just that. public int UpdateFrom5() { - SchemaBuilder.AlterTable("PropertyRecord", table => table - .AddColumn("RewriteOutputCondition", c => c.Unlimited()) - ); - - foreach (var property in _propertyRecordRepository.Table) - if (property.RewriteOutput) property.RewriteOutputCondition = "true"; + MigratePropertyRecordToRewriteOutputCondition(); return 6; } -#pragma warning restore CS0618 public int UpdateFrom6() { - SchemaBuilder.AlterTable("LayoutRecord", t => t.AddColumn("GUIdentifier", - column => column.WithLength(68))); - - var layoutRecords = _layoutRepository.Table.Where(l => l.GUIdentifier == null || l.GUIdentifier == "").ToList(); - foreach (var layout in layoutRecords) { - layout.GUIdentifier = Guid.NewGuid().ToString(); + if (IsUpgradingFromOrchard_1_10_x_Version_6) { + MigratePropertyRecordToRewriteOutputCondition(); + } + else { + // This change was originally UpdateFrom5 on 1.10.x and UpdateFrom6 on dev. + SchemaBuilder.AlterTable("LayoutRecord", table => + table.AddColumn("GUIdentifier", column => column.WithLength(68))); + + var layoutRecords = _layoutRepository.Table.Where(l => l.GUIdentifier == null || l.GUIdentifier == "").ToList(); + foreach (var layout in layoutRecords) { + layout.GUIdentifier = Guid.NewGuid().ToString(); + } } return 7; } + // This change was originally in UpdateFrom5 on dev, but didn't exist on 1.10.x. + private void MigratePropertyRecordToRewriteOutputCondition() { + SchemaBuilder.AlterTable("PropertyRecord", table => table + .AddColumn("RewriteOutputCondition", c => c.Unlimited()) + ); + + foreach (var property in _propertyRecordRepository.Table) +#pragma warning disable CS0618 // Type or member is obsolete + // Reading this obsolete property to migrate its data to a new one. + if (property.RewriteOutput) property.RewriteOutputCondition = "true"; +#pragma warning restore CS0618 // Type or member is obsolete + } } } diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Settings/ProjectionPartEditorEvents.cs b/src/Orchard.Web/Modules/Orchard.Projections/Settings/ProjectionPartEditorEvents.cs index f66f0059676..8460e2ad59a 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Settings/ProjectionPartEditorEvents.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Settings/ProjectionPartEditorEvents.cs @@ -62,10 +62,10 @@ public override IEnumerable TypePartEditorUpdate(ContentTypeP model.QueryRecordEntries = GetQueriesRecordEntry(); - if(updateModel.TryUpdateModel(model, "ProjectionPartSettings", null, null)) { - if (model.FilterQueryRecordsId != null && model.FilterQueryRecordsId.Count()>0) { + if (updateModel.TryUpdateModel(model, "ProjectionPartSettings", null, null)) { + if (model.FilterQueryRecordsId != null && model.FilterQueryRecordsId.Count() > 0) { // check if default query selected is in filter queries list - if (!model.FilterQueryRecordsId.Contains(model.QueryLayoutRecordId) && model.QueryLayoutRecordId!="-1") { + if (!model.FilterQueryRecordsId.Contains(model.QueryLayoutRecordId) && model.QueryLayoutRecordId != "-1") { updateModel.AddModelError("ProjectionPart", T("The default query must be one of the selected queries")); } @@ -139,7 +139,7 @@ public void ContentTypeImported(ContentTypeImportedContext context) { // from identity part of the query and guid of the layout find reference settings.QueryLayoutRecordId = string.IsNullOrWhiteSpace(settings.IdentityQueryLayoutRecord) ? "-1" : GetQueryLayoutRecord(settings.IdentityQueryLayoutRecord); - + if (!string.IsNullOrWhiteSpace(settings.IdentityFilterQueryRecord)) { List identityForFilterQuery = new List(); foreach (var record in settings.IdentityFilterQueryRecord.Split('&').ToList()) { @@ -149,10 +149,11 @@ public void ContentTypeImported(ContentTypeImportedContext context) { } } settings.FilterQueryRecordId = string.Join("&", identityForFilterQuery); - } else { + } + else { settings.FilterQueryRecordId = string.Empty; } - + _contentDefinitionManager.AlterTypeDefinition(context.ContentTypeDefinition.Name, cfg => cfg .WithPart(part.PartDefinition.Name, pb => pb @@ -203,7 +204,7 @@ private string GetIdentityQueryLayout(string record) { // if is present only -1, the default query has not been selected return ids[0]; } - else { + else { // ids[0] is id of query // ids[1] is record id of layout var identityQueryLayout = string.Empty; diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Web.config b/src/Orchard.Web/Modules/Orchard.Projections/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Projections/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Projections/packages.config b/src/Orchard.Web/Modules/Orchard.Projections/packages.config index b536bbfa970..571aa7defed 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Projections/packages.config @@ -10,4 +10,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.PublishLater/Web.config b/src/Orchard.Web/Modules/Orchard.PublishLater/Web.config index c8209404f14..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.PublishLater/Web.config +++ b/src/Orchard.Web/Modules/Orchard.PublishLater/Web.config @@ -39,38 +39,38 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - + + + diff --git a/src/Orchard.Web/Modules/Orchard.Recipes/Module.txt b/src/Orchard.Web/Modules/Orchard.Recipes/Module.txt index a9cd52ec6e8..37e60333fb0 100644 --- a/src/Orchard.Web/Modules/Orchard.Recipes/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Recipes/Module.txt @@ -7,3 +7,4 @@ OrchardVersion: 1.10.3 Description: Provides Orchard Recipes. FeatureDescription: Implementation of Orchard recipes. Category: Core +Dependencies: PackagingServices diff --git a/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeManager.cs b/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeManager.cs index 41ae6ac9cb6..434b338503b 100644 --- a/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeManager.cs +++ b/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeManager.cs @@ -3,6 +3,7 @@ using log4net; using Orchard.Data; using Orchard.Logging; +using Orchard.Mvc; using Orchard.Recipes.Events; using Orchard.Recipes.Models; @@ -12,17 +13,38 @@ public class RecipeManager : Component, IRecipeManager { private readonly IRecipeScheduler _recipeScheduler; private readonly IRecipeExecuteEventHandler _recipeExecuteEventHandler; private readonly IRepository _recipeStepResultRecordRepository; + private readonly IHttpContextAccessor _httpContextAccessor; public RecipeManager( IRecipeStepQueue recipeStepQueue, IRecipeScheduler recipeScheduler, IRecipeExecuteEventHandler recipeExecuteEventHandler, - IRepository recipeStepResultRecordRepository) { + IRepository recipeStepResultRecordRepository, + IHttpContextAccessor httpContextAccessor) { _recipeStepQueue = recipeStepQueue; _recipeScheduler = recipeScheduler; _recipeExecuteEventHandler = recipeExecuteEventHandler; _recipeStepResultRecordRepository = recipeStepResultRecordRepository; + _httpContextAccessor = httpContextAccessor; + + RecipeExecutionTimeout = 600; + } + + public int RecipeExecutionTimeout { + get; set; + // The public setter allows injecting this from Sites.MyTenant.Config or Sites.config, by using + // an AutoFac component: + /* + + + + + + + */ } public string Execute(Recipe recipe) { @@ -35,6 +57,12 @@ public string Execute(Recipe recipe) { return null; } + // Sets the request timeout to a configurable amount of seconds to give enough time to execute custom recipes. + var httpContext = _httpContextAccessor.Current(); + if (httpContext != null) { + httpContext.Server.ScriptTimeout = RecipeExecutionTimeout; + } + var executionId = Guid.NewGuid().ToString("n"); ThreadContext.Properties["ExecutionId"] = executionId; diff --git a/src/Orchard.Web/Modules/Orchard.Recipes/Web.config b/src/Orchard.Web/Modules/Orchard.Recipes/Web.config index 15fb4cc72fe..10420d55395 100644 --- a/src/Orchard.Web/Modules/Orchard.Recipes/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Recipes/Web.config @@ -37,24 +37,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -67,8 +67,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Redis/Orchard.Redis.csproj b/src/Orchard.Web/Modules/Orchard.Redis/Orchard.Redis.csproj index 858815251b3..ea5fcec28ed 100644 --- a/src/Orchard.Web/Modules/Orchard.Redis/Orchard.Redis.csproj +++ b/src/Orchard.Web/Modules/Orchard.Redis/Orchard.Redis.csproj @@ -177,4 +177,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Redis/Web.config b/src/Orchard.Web/Modules/Orchard.Redis/Web.config index 7a21a391b4f..804fac07aba 100644 --- a/src/Orchard.Web/Modules/Orchard.Redis/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Redis/Web.config @@ -33,24 +33,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - + + + diff --git a/src/Orchard.Web/Modules/Orchard.Redis/packages.config b/src/Orchard.Web/Modules/Orchard.Redis/packages.config index dcc3623081a..15b9d28a1d6 100644 --- a/src/Orchard.Web/Modules/Orchard.Redis/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Redis/packages.config @@ -7,4 +7,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Resources/Web.config b/src/Orchard.Web/Modules/Orchard.Resources/Web.config index b09f00fc3c5..0a4b7f43f38 100644 --- a/src/Orchard.Web/Modules/Orchard.Resources/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Resources/Web.config @@ -40,42 +40,42 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Roles/Activities/RoleEventActivity.cs b/src/Orchard.Web/Modules/Orchard.Roles/Activities/RoleEventActivity.cs new file mode 100644 index 00000000000..d48415838ae --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Roles/Activities/RoleEventActivity.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using Orchard.Environment.Extensions; +using Orchard.Localization; +using Orchard.Workflows.Models; +using Orchard.Workflows.Services; + +namespace Orchard.Roles.Activities { + [OrchardFeature("Orchard.Roles.Workflows")] + public class RoleEventActivity : Event { + public Localizer T { get; set; } + + public RoleEventActivity() { + T = NullLocalizer.Instance; + } + + public override bool CanStartWorkflow { + get { return true; } + } + + public override string Name { + get { + return "OnRoleEvent"; + } + } + + public override LocalizedString Category { + get { + return T("Roles"); + } + } + + public override LocalizedString Description { + get { + return T("Manage Role Event"); + } + } + + public override IEnumerable Execute(WorkflowContext workflowContext, ActivityContext activityContext) { + string operatore = workflowContext.Tokens["Action"].ToString(); + LocalizedString msg = T(operatore); + yield return msg; + } + + public override IEnumerable GetPossibleOutcomes(WorkflowContext workflowContext, ActivityContext activityContext) { + return new[] { + T("Created"), + T("Removed"), + T("Renamed"), + T("UserAdded"), + T("UserRemoved"), + T("PermissionAdded"), + T("PermissionRemoved") + }; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Roles/Events/RoleEventHandler.cs b/src/Orchard.Web/Modules/Orchard.Roles/Events/RoleEventHandler.cs new file mode 100644 index 00000000000..6dd6af0a824 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Roles/Events/RoleEventHandler.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using Orchard.Environment.Extensions; +using Orchard.Workflows.Services; + +namespace Orchard.Roles.Events { + [OrchardFeature("Orchard.Roles.Workflows")] + public class RoleEventHandler : IRoleEventHandler { + private readonly IWorkflowManager _workflowManager; + + public RoleEventHandler(IWorkflowManager workflowManager) { + _workflowManager = workflowManager; + } + + public void Created(RoleCreatedContext context) { + _workflowManager.TriggerEvent("OnRoleEvent", + null, + () => new Dictionary { + { "Role", context.Role }, + { "Action", "Created" } }); + } + + public void PermissionAdded(PermissionAddedContext context) { + _workflowManager.TriggerEvent("OnRoleEvent", + null, + () => new Dictionary { + { "Role", context.Role }, + { "Permission", context.Permission }, + { "Action", "PermissionAdded" } }); + } + + public void PermissionRemoved(PermissionRemovedContext context) { + _workflowManager.TriggerEvent("OnRoleEvent", + null, + () => new Dictionary { + { "Role", context.Role }, + { "Permission", context.Permission }, + { "Action", "PermissionRemoved" } }); + } + + public void Removed(RoleRemovedContext context) { + _workflowManager.TriggerEvent("OnRoleEvent", + null, + () => new Dictionary { + { "Role", context.Role }, + { "Action", "Removed" } }); + } + + public void Renamed(RoleRenamedContext context) { + _workflowManager.TriggerEvent("OnRoleEvent", + null, + () => new Dictionary { + { "PreviousName", context.PreviousRoleName }, + { "NewName", context.NewRoleName }, + { "Action", "Renamed" } }); + } + + public void UserAdded(UserAddedContext context) { + // Content of workflow event is the user + var content = context.User.ContentItem; + _workflowManager.TriggerEvent("OnRoleEvent", + content, + () => new Dictionary { + { "Role", context.Role }, + { "User", context.User }, + { "Action", "UserAdded" } }); + } + + public void UserRemoved(UserRemovedContext context) { + // Content of workflow event is the user + var content = context.User.ContentItem; + _workflowManager.TriggerEvent("OnRoleEvent", + content, + () => new Dictionary { + { "Role", context.Role }, + { "User", context.User }, + { "Action", "UserRemoved" } }); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Roles/Orchard.Roles.csproj b/src/Orchard.Web/Modules/Orchard.Roles/Orchard.Roles.csproj index 85cc3358086..35fae79ea25 100644 --- a/src/Orchard.Web/Modules/Orchard.Roles/Orchard.Roles.csproj +++ b/src/Orchard.Web/Modules/Orchard.Roles/Orchard.Roles.csproj @@ -95,6 +95,7 @@
+ @@ -111,6 +112,7 @@ + @@ -271,4 +273,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Roles/Web.config b/src/Orchard.Web/Modules/Orchard.Roles/Web.config index 854be8b67fa..0df49e40c1c 100644 --- a/src/Orchard.Web/Modules/Orchard.Roles/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Roles/Web.config @@ -29,6 +29,7 @@ + @@ -39,24 +40,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +70,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Roles/packages.config b/src/Orchard.Web/Modules/Orchard.Roles/packages.config index 2ae22b193cd..51c3aaef7f0 100644 --- a/src/Orchard.Web/Modules/Orchard.Roles/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Roles/packages.config @@ -6,4 +6,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Rules/Web.config b/src/Orchard.Web/Modules/Orchard.Rules/Web.config index a8ba082bc71..499302ccce4 100644 --- a/src/Orchard.Web/Modules/Orchard.Rules/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Rules/Web.config @@ -42,24 +42,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -72,8 +72,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Scripting.CSharp/Web.config b/src/Orchard.Web/Modules/Orchard.Scripting.CSharp/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.Scripting.CSharp/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Scripting.CSharp/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Scripting.Dlr/Web.config b/src/Orchard.Web/Modules/Orchard.Scripting.Dlr/Web.config index 7a21a391b4f..804fac07aba 100644 --- a/src/Orchard.Web/Modules/Orchard.Scripting.Dlr/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Scripting.Dlr/Web.config @@ -33,24 +33,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - + + + diff --git a/src/Orchard.Web/Modules/Orchard.Scripting/Web.config b/src/Orchard.Web/Modules/Orchard.Scripting/Web.config index 7a21a391b4f..804fac07aba 100644 --- a/src/Orchard.Web/Modules/Orchard.Scripting/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Scripting/Web.config @@ -33,24 +33,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - + + + diff --git a/src/Orchard.Web/Modules/Orchard.Search/BlogPostsLocalNavigationProvider.cs b/src/Orchard.Web/Modules/Orchard.Search/BlogPostsLocalNavigationProvider.cs new file mode 100644 index 00000000000..03acc66387d --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/BlogPostsLocalNavigationProvider.cs @@ -0,0 +1,42 @@ +using System.Linq; +using Orchard.Blogs; +using Orchard.Blogs.Services; +using Orchard.Environment.Extensions; +using Orchard.Localization; +using Orchard.Security; +using Orchard.UI.Navigation; + +namespace Orchard.Search { + [OrchardFeature("Orchard.Search.Blogs")] + public class BlogPostsLocalNavigationProvider : INavigationProvider { + private readonly IBlogService _blogService; + private readonly IAuthorizationService _authorizationService; + private readonly IWorkContextAccessor _workContextAccessor; + + public BlogPostsLocalNavigationProvider( + IBlogService blogService, + IAuthorizationService authorizationService, + IWorkContextAccessor workContextAccessor) { + + T = NullLocalizer.Instance; + _blogService = blogService; + _authorizationService = authorizationService; + _workContextAccessor = workContextAccessor; + } + + public Localizer T { get; set; } + + public string MenuName { + get { return "blogposts-navigation"; } + } + public void GetNavigation(NavigationBuilder builder) { + var blogId = 0; + int.TryParse(_workContextAccessor.GetContext().HttpContext.Request.RequestContext.RouteData.Values["blogId"]?.ToString(), out blogId); + if (blogId > 0) { + builder.Add(T("Search Posts"), "2.0", item => item.Action("Index", "BlogSearch", new { area = "Orchard.Search", blogId }) + .LocalNav() + .Permission(Permissions.MetaListOwnBlogs)); + } + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Constants.cs b/src/Orchard.Web/Modules/Orchard.Search/Constants.cs new file mode 100644 index 00000000000..696a300cadf --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/Constants.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using Orchard.Environment.Extensions; + +namespace Orchard.Search { + [OrchardFeature("Orchard.Search.Blogs")] + public class BlogSearchConstants { + public static string ADMIN_BLOGPOSTS_INDEX = "AdminBlogPosts"; + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Controllers/BlogSearchController.cs b/src/Orchard.Web/Modules/Orchard.Search/Controllers/BlogSearchController.cs new file mode 100644 index 00000000000..6497eaa9bc8 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/Controllers/BlogSearchController.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web.Mvc; +using Orchard.Collections; +using Orchard.ContentManagement; +using Orchard.ContentManagement.MetaData; +using Orchard.DisplayManagement; +using Orchard.Environment.Extensions; +using Orchard.Indexing; +using Orchard.Localization; +using Orchard.Localization.Services; +using Orchard.Logging; +using Orchard.Search.Helpers; +using Orchard.Search.Models; +using Orchard.Search.Services; +using Orchard.Security; +using Orchard.Settings; +using Orchard.UI.Admin; +using Orchard.UI.Navigation; +using Orchard.UI.Notify; + +namespace Orchard.Search.Controllers { + [OrchardFeature("Orchard.Search.Blogs")] + [Admin] + public class BlogSearchController : Controller { + private readonly ISearchService _searchService; + private readonly ISiteService _siteService; + private readonly IIndexManager _indexManager; + private readonly IContentDefinitionManager _contentDefinitionManager; + private readonly IContentManager _contentManager; + private readonly IAuthorizer _authorizer; + private readonly ICultureManager _cultureManager; + private readonly INavigationManager _navigationManager; + + public BlogSearchController( + IOrchardServices orchardServices, + ISearchService searchService, + ISiteService siteService, + IIndexManager indexManager, + IContentDefinitionManager contentDefinitionManager, + IContentManager contentManager, + IAuthorizer authorizer, + ICultureManager cultureManager, + INavigationManager navigationManager, + IShapeFactory shapeFactory) { + + _searchService = searchService; + _siteService = siteService; + Services = orchardServices; + _indexManager = indexManager; + _contentDefinitionManager = contentDefinitionManager; + _contentManager = contentManager; + _authorizer = authorizer; + _cultureManager = cultureManager; + _navigationManager = navigationManager; + Shape = shapeFactory; + T = NullLocalizer.Instance; + Logger = NullLogger.Instance; + } + + public IOrchardServices Services { get; set; } + public ILogger Logger { get; set; } + public Localizer T { get; set; } + public dynamic Shape { get; set; } + + public ActionResult Index(int blogId, PagerParameters pagerParameters, string searchText = "") { + var pager = new Pager(_siteService.GetSiteSettings(), pagerParameters); + var searchSettingsPart = Services.WorkContext.CurrentSite.As(); + + IPageOfItems searchHits = new PageOfItems(new ISearchHit[] { }); + try { + if (!string.IsNullOrWhiteSpace(searchText)) { + var searchableTypes = new List(); + // add the type to the list of types we will filter for + // BlogPost for now but we would add more types in the future (i.e. "Article") + searchableTypes.Add("BlogPost"); + var searchBuilder = _indexManager.HasIndexProvider() + ? _indexManager + .GetSearchIndexProvider() + .CreateSearchBuilder(BlogSearchConstants.ADMIN_BLOGPOSTS_INDEX) + : new NullSearchBuilder(); + + searchBuilder + .Parse(searchSettingsPart + .GetSearchFields(BlogSearchConstants.ADMIN_BLOGPOSTS_INDEX), + searchText); + + // filter by Blog + searchBuilder + .WithField("container-id", blogId) + .Mandatory() + .NotAnalyzed() + .AsFilter(); + + foreach (var searchableType in searchableTypes) { + // filter by type + searchBuilder + .WithField("type", searchableType) + .NotAnalyzed() + .AsFilter(); + } + // pagination + var totalCount = searchBuilder.Count(); + if (pager != null) { + searchBuilder = searchBuilder + .Slice( + (pager.Page > 0 ? pager.Page - 1 : 0) * pager.PageSize, + pager.PageSize); + } + // search + var searchResults = searchBuilder.Search(); + // prepare the shape for the page + searchHits = new PageOfItems(searchResults.Select(searchHit => searchHit)) { + PageNumber = pager != null ? pager.Page : 0, + PageSize = pager != null ? (pager.PageSize != 0 ? pager.PageSize : totalCount) : totalCount, + TotalItemCount = totalCount + }; + } + + } + catch (Exception exception) { + Logger.Error(T("Invalid search query: {0}", exception.Message).Text); + Services.Notifier.Error(T("Invalid search query: {0}", exception.Message)); + } + + var list = Services.New.List(); + foreach (var contentItem in Services.ContentManager.GetMany(searchHits.Select(x => x.ContentItemId), VersionOptions.Latest, QueryHints.Empty)) { + // ignore search results which content item has been removed + if (contentItem == null) { + searchHits.TotalItemCount--; + continue; + } + + list.Add(Services.ContentManager.BuildDisplay(contentItem, "SummaryAdmin")); + } + + var pagerShape = Services.New.Pager(pager).TotalItemCount(searchHits.TotalItemCount); + + var viewModel = Services.New.ViewModel() + .ContentItems(list) + .Pager(pagerShape) + .SearchText(searchText) + .BlogId(blogId); + + // Adds LocalMenus; + var menuItems = _navigationManager.BuildMenu("blogposts-navigation"); + var request = Services.WorkContext.HttpContext.Request; + + // Set the currently selected path + Stack selectedPath = NavigationHelper.SetSelectedPath(menuItems, request, request.RequestContext.RouteData); + + // Populate local nav + dynamic localMenuShape = Shape.LocalMenu().MenuName("local-admin"); + + NavigationHelper.PopulateLocalMenu(Shape, localMenuShape, localMenuShape, menuItems); + Services.WorkContext.Layout.LocalNavigation.Add(localMenuShape); + + return View(viewModel); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Migrations.cs b/src/Orchard.Web/Modules/Orchard.Search/Migrations.cs index a680469c078..f03156f00e2 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Migrations.cs +++ b/src/Orchard.Web/Modules/Orchard.Search/Migrations.cs @@ -69,4 +69,23 @@ public int Create() { return 1; } } + + [OrchardFeature("Orchard.Search.Blogs")] + public class BlogsMigration : DataMigrationImpl { + private readonly IIndexManager _indexManager; + + public BlogsMigration(IIndexManager indexManager) { + _indexManager = indexManager; + } + + public int Create() { + + _indexManager.GetSearchIndexProvider().CreateIndex(BlogSearchConstants.ADMIN_BLOGPOSTS_INDEX); + + ContentDefinitionManager.AlterTypeDefinition("BlogPost", cfg => cfg.WithSetting("TypeIndexing.Indexes", BlogSearchConstants.ADMIN_BLOGPOSTS_INDEX + ":latest")); + + return 1; + } + } + } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Module.txt b/src/Orchard.Web/Modules/Orchard.Search/Module.txt index ccbce4fc63d..c40d8c5ad85 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Search/Module.txt @@ -26,4 +26,9 @@ Features: Name: Media Library Search Description: Provides search menu item in the Media Library explorer. Dependencies: Orchard.MediaLibrary, Orchard.Search + Category: Search + Orchard.Search.Blogs: + Name: Blog posts Search + Description: Provides search menu item in the Blog section. + Dependencies: Orchard.Blogs, Orchard.Search Category: Search \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj b/src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj index c992378c017..5450b6d6eb9 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj +++ b/src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj @@ -93,7 +93,10 @@ + + + @@ -134,6 +137,10 @@ Orchard.Core $(MvcBuildViews) + + {63FBD4D9-E1DA-4A7B-AA6A-D6074FE50867} + Orchard.Blogs + {73a7688a-5bd3-4f7e-adfa-ce36c5a10e3b} Orchard.MediaLibrary @@ -207,6 +214,7 @@ + 10.0 diff --git a/src/Orchard.Web/Modules/Orchard.Search/Routes.cs b/src/Orchard.Web/Modules/Orchard.Search/Routes.cs index 8ae194e8fb3..ab0c3d12370 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Routes.cs +++ b/src/Orchard.Web/Modules/Orchard.Search/Routes.cs @@ -36,6 +36,21 @@ public void GetRoutes(ICollection routes) { {"area", "Orchard.Search"} }, new MvcRouteHandler()) + }, + new RouteDescriptor { + Priority = 5, + Route = new Route("Admin/Search/BlogSearch/{blogId}", + new RouteValueDictionary { + {"area", "Orchard.Search"}, + {"controller", "BlogSearch"}, + {"action", "Index"}, + {"blogId", UrlParameter.Optional} + }, + null, + new RouteValueDictionary { + {"area", "Orchard.Search"} + }, + new MvcRouteHandler()) } }; diff --git a/src/Orchard.Web/Modules/Orchard.Search/Views/BlogSearch/Index.cshtml b/src/Orchard.Web/Modules/Orchard.Search/Views/BlogSearch/Index.cshtml new file mode 100644 index 00000000000..e0a9b88de91 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/Views/BlogSearch/Index.cshtml @@ -0,0 +1,21 @@ +@{ + var pageTitle = T("Search Content"); + Layout.Title = pageTitle; +} + +@using (Html.BeginFormAntiForgeryPost(Url.Action("index", new { controller = "BlogSearch", area = "Orchard.Search", blogId = Model.BlogId }), FormMethod.Get)) { + + @Html.TextBox("searchText", (string)Model.SearchText, new { @class = "text medium", autofocus = "autofocus" }) + + + +
+ @Display(Model.ContentItems) +
+ + if (HasText(Model.SearchText) && Model.ContentItems.Items.Count == 0) { + @T("There are no results") + } + + @Display(Model.Pager) +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Web.config b/src/Orchard.Web/Modules/Orchard.Search/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Search/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.SecureSocketsLayer/Web.config b/src/Orchard.Web/Modules/Orchard.SecureSocketsLayer/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.SecureSocketsLayer/Web.config +++ b/src/Orchard.Web/Modules/Orchard.SecureSocketsLayer/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Setup/Web.config b/src/Orchard.Web/Modules/Orchard.Setup/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.Setup/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Setup/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Tags/Web.config b/src/Orchard.Web/Modules/Orchard.Tags/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.Tags/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Tags/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Tags/packages.config b/src/Orchard.Web/Modules/Orchard.Tags/packages.config index b536bbfa970..571aa7defed 100644 --- a/src/Orchard.Web/Modules/Orchard.Tags/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Tags/packages.config @@ -10,4 +10,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.TaskLease/Web.config b/src/Orchard.Web/Modules/Orchard.TaskLease/Web.config index 7a21a391b4f..804fac07aba 100644 --- a/src/Orchard.Web/Modules/Orchard.TaskLease/Web.config +++ b/src/Orchard.Web/Modules/Orchard.TaskLease/Web.config @@ -33,24 +33,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - + + + diff --git a/src/Orchard.Web/Modules/Orchard.Taxonomies/Drivers/TermPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Taxonomies/Drivers/TermPartDriver.cs index 6491a6cdcd4..b3299b9aa59 100644 --- a/src/Orchard.Web/Modules/Orchard.Taxonomies/Drivers/TermPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Taxonomies/Drivers/TermPartDriver.cs @@ -52,7 +52,11 @@ protected override DriverResult Display(TermPart part, string displayType, dynam var pagerParameters = new PagerParameters(); var httpContext = _httpContextAccessor.Current(); if (httpContext != null) { - pagerParameters.Page = Convert.ToInt32(httpContext.Request.QueryString["page"]); + // Check if "page" parameter is a valid number. + int page = 0; + if (int.TryParse(httpContext.Request.QueryString["page"], out page)) { + pagerParameters.Page = page; + } } var pager = new Pager(_siteService.GetSiteSettings(), pagerParameters); diff --git a/src/Orchard.Web/Modules/Orchard.Taxonomies/Navigation/TaxonomyNavigationProvider.cs b/src/Orchard.Web/Modules/Orchard.Taxonomies/Navigation/TaxonomyNavigationProvider.cs index 6ca41931c69..681e6709539 100644 --- a/src/Orchard.Web/Modules/Orchard.Taxonomies/Navigation/TaxonomyNavigationProvider.cs +++ b/src/Orchard.Web/Modules/Orchard.Taxonomies/Navigation/TaxonomyNavigationProvider.cs @@ -22,8 +22,16 @@ public TaxonomyNavigationProvider( ITaxonomyService taxonomyService) { _contentManager = contentManager; _taxonomyService = taxonomyService; + + _termsMemory = new Dictionary(); } + // Prevent doing the same query for terms more than once on a same request + // in case we are building menus from the same starting taxonomies. Key is a + // string to "combine" the Id of the root TermPart and the flag telling to + // add that root to the results. + private Dictionary _termsMemory; + public IEnumerable Filter(IEnumerable items) { foreach (var item in items) { @@ -34,14 +42,21 @@ public IEnumerable Filter(IEnumerable items) { var rootTerm = _taxonomyService.GetTerm(taxonomyNavigationPart.TermId); TermPart[] allTerms; - + string memoryKey; if (rootTerm != null) { - // if DisplayRootTerm is specified add it to the menu items to render - allTerms = _taxonomyService.GetChildren(rootTerm, taxonomyNavigationPart.DisplayRootTerm).ToArray(); + memoryKey = $"{rootTerm.Id}_{taxonomyNavigationPart.DisplayRootTerm}"; + if (!_termsMemory.ContainsKey(memoryKey)) { + // if DisplayRootTerm is specified add it to the menu items to render + _termsMemory[memoryKey] = _taxonomyService.GetChildren(rootTerm, taxonomyNavigationPart.DisplayRootTerm).ToArray(); + } } else { - allTerms = _taxonomyService.GetTerms(taxonomyNavigationPart.TaxonomyId).ToArray(); + memoryKey = taxonomyNavigationPart.TaxonomyId.ToString(); + if (!_termsMemory.ContainsKey(memoryKey)) { + _termsMemory[memoryKey] = _taxonomyService.GetTerms(taxonomyNavigationPart.TaxonomyId).ToArray(); + } } + allTerms = _termsMemory[memoryKey]; var rootLevel = rootTerm != null ? rootTerm.GetLevels() diff --git a/src/Orchard.Web/Modules/Orchard.Taxonomies/Orchard.Taxonomies.csproj b/src/Orchard.Web/Modules/Orchard.Taxonomies/Orchard.Taxonomies.csproj index be842a8e223..7aae8071047 100644 --- a/src/Orchard.Web/Modules/Orchard.Taxonomies/Orchard.Taxonomies.csproj +++ b/src/Orchard.Web/Modules/Orchard.Taxonomies/Orchard.Taxonomies.csproj @@ -87,7 +87,6 @@ - ..\..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.7\lib\net45\System.Net.Http.Formatting.dll @@ -348,4 +347,4 @@
- \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Taxonomies/Views/EditorTemplates/Fields/TaxonomyField.cshtml b/src/Orchard.Web/Modules/Orchard.Taxonomies/Views/EditorTemplates/Fields/TaxonomyField.cshtml index 02d9d615b46..294ead70c26 100644 --- a/src/Orchard.Web/Modules/Orchard.Taxonomies/Views/EditorTemplates/Fields/TaxonomyField.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Taxonomies/Views/EditorTemplates/Fields/TaxonomyField.cshtml @@ -11,6 +11,8 @@ int termIndex = 0; var settings = Model.Settings; + + var noSelectionId = Guid.NewGuid(); }
@@ -21,26 +23,31 @@ @Model.Settings.Hint } -
    - @foreach (var entry in Model.Terms) { - var ti = termIndex; -
  • - @* Tabs for levels *@ @for (var i = 1; i <= entry.GetLevels(); i++) {   } - @{ - var disabled = !entry.Selectable || (Model.Settings.LeavesOnly && Model.Terms.Any(t => t.Path.Contains(entry.Path + entry.Id))); - if (Model.Settings.SingleChoice) { - disabled="disabled" } type="radio" value="@Model.Terms[ti].Id" @if (entry.Id == Model.SingleTermId) { checked="checked" } name="@Html.FieldNameFor(m => m.SingleTermId)" id="@Html.FieldIdFor(m => m.Terms[ti].IsChecked)" data-term="@entry.Name.ToLower()" /> - } - else { - disabled="disabled" } type="checkbox" value="true" @if (entry.IsChecked) { checked="checked" } name="@Html.FieldNameFor(m => m.Terms[ti].IsChecked)" id="@Html.FieldIdFor(m => m.Terms[ti].IsChecked)" data-term="@entry.Name.ToLower()" /> - } +
      + @if (Model.Settings.SingleChoice && !settings.Required) { +
    • + checked="checked" } name="@Html.FieldNameFor(m => m.SingleTermId)" id="@noSelectionId" data-term="@T("No selection")" /> + +
    • + } + @foreach (var entry in Model.Terms) { + var ti = termIndex; +
    • + @* Tabs for levels *@ @for (var i = 1; i <= entry.GetLevels(); i++) { } + @{ + var disabled = !entry.Selectable || (Model.Settings.LeavesOnly && Model.Terms.Any(t => t.Path.Contains(entry.Path + entry.Id))); + if (Model.Settings.SingleChoice) { + disabled="disabled" } type="radio" value="@Model.Terms[ti].Id" @if (entry.Id == Model.SingleTermId) { checked="checked" } name="@Html.FieldNameFor(m => m.SingleTermId)" id="@Html.FieldIdFor(m => m.Terms[ti].IsChecked)" data-term="@entry.Name.ToLower()" /> + } else { + disabled="disabled" } type="checkbox" value="true" @if (entry.IsChecked) { checked="checked" } name="@Html.FieldNameFor(m => m.Terms[ti].IsChecked)" id="@Html.FieldIdFor(m => m.Terms[ti].IsChecked)" data-term="@entry.Name.ToLower()" /> } - @Html.HiddenFor(m => m.Terms[ti].Id) - -
    • - termIndex++; - } -
    + } + @Html.HiddenFor(m => m.Terms[ti].Id) + +
  • + termIndex++; + } +
@if (Model.TaxonomyId == 0) {

@T("You haven't specified a taxonomy for {0}", Model.DisplayName)

diff --git a/src/Orchard.Web/Modules/Orchard.Taxonomies/Web.config b/src/Orchard.Web/Modules/Orchard.Taxonomies/Web.config index a019934e78e..f0c7ba9c3a2 100644 --- a/src/Orchard.Web/Modules/Orchard.Taxonomies/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Taxonomies/Web.config @@ -38,24 +38,36 @@ - - - - + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -68,8 +80,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Taxonomies/packages.config b/src/Orchard.Web/Modules/Orchard.Taxonomies/packages.config index c9692138194..5e7dacf19a0 100644 --- a/src/Orchard.Web/Modules/Orchard.Taxonomies/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Taxonomies/packages.config @@ -13,4 +13,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Templates/Web.config b/src/Orchard.Web/Modules/Orchard.Templates/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.Templates/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Templates/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Themes/Web.config b/src/Orchard.Web/Modules/Orchard.Themes/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.Themes/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Themes/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/ContentTokens.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/ContentTokens.cs index fb26b250079..e6ddfe22f9d 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/ContentTokens.cs +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/ContentTokens.cs @@ -26,6 +26,9 @@ public ContentTokens(IContentManager contentManager, UrlHelper urlHelper) { public Localizer T { get; set; } public void Describe(DescribeContext context) { + context.For("ContentItem", T("Content Items"), T("The context to access specific content items.")) + .Token("Id:*", T("Content Item by Id"), T("The content item with the specified id.")); + context.For("Content", T("Content Items"), T("Content Items")) .Token("Id", T("Content Id"), T("Numeric primary key value of content.")) .Token("Author", T("Content Author"), T("Person in charge of the content."), "User") @@ -36,8 +39,7 @@ public void Describe(DescribeContext context) { .Token("DisplayUrl", T("Display Url"), T("Url to display the content."), "Url") .Token("EditUrl", T("Edit Url"), T("Url to edit the content."), "Url") .Token("Container", T("Container"), T("The container Content Item."), "Content") - .Token("Body", T("Body"), T("The body text of the content item."), "Text") - ; + .Token("Body", T("Body"), T("The body text of the content item."), "Text"); // Token descriptors for fields foreach (var typeDefinition in _contentManager.GetContentTypeDefinitions()) { @@ -72,26 +74,57 @@ public void Describe(DescribeContext context) { } public void Evaluate(EvaluateContext context) { + context.For("ContentItem", _contentManager) + .Token( + token => token.StartsWith("Id:", StringComparison.OrdinalIgnoreCase) ? ContentManagerGetToken(token) : "", + (token, cm) => { + // token is Id:* + if (token != "") { + var id = token.Substring("Id:".Length); + return cm.Get(Convert.ToInt32(id)); + } + else { return null; } + }) + .Chain( + token => { + var cleanToken = ContentManagerGetToken(token); // is Id:* + if (string.IsNullOrWhiteSpace(cleanToken)) return null; + int cleanTokenLength = cleanToken.Length; + var subTokens = token.Length > cleanTokenLength ? token.Substring(cleanToken.Length + 1) : ""; + return new Tuple( + cleanToken, //The specific Token Id:*, it is the key + subTokens //The subsequent Tokens (i.e Fields.PartName.FieldName) + ); + }, + "Content", + (token, cm) => { + // token is Id:* + + if (token != "") { + var id = token.Substring("Id:".Length); + return cm.Get(Convert.ToInt32(id)); + } + else { return null; } + }); context.For("Content") - .Token("Id", content => content != null ? content.Id : 0) - .Token("Author", AuthorName) - .Chain("Author", "User", content => content != null ? content.As().Owner : null) - .Token("Date", Date) - .Chain("Date", "Date", Date) - .Token("Identity", content => content != null ? _contentManager.GetItemMetadata(content).Identity.ToString() : String.Empty) - .Token("ContentType", content => content != null ? content.ContentItem.TypeDefinition.DisplayName : String.Empty) - .Chain("ContentType", "TypeDefinition", content => content != null ? content.ContentItem.TypeDefinition : null) - .Token("DisplayText", DisplayText) - .Chain("DisplayText", "Text", DisplayText) - .Token("DisplayUrl", DisplayUrl) - .Chain("DisplayUrl", "Url", DisplayUrl) - .Token("EditUrl", EditUrl) - .Chain("EditUrl", "Url", EditUrl) - .Token("Container", content => DisplayText(Container(content))) - .Chain("Container", "Content", Container) - .Token("Body", Body) - .Chain("Body", "Text", Body) - ; + .Token("Id", content => content != null ? content.Id : 0) + .Token("Author", AuthorName) + .Chain("Author", "User", content => content != null ? content.As().Owner : null) + .Token("Date", Date) + .Chain("Date", "Date", Date) + .Token("Identity", content => content != null ? _contentManager.GetItemMetadata(content).Identity.ToString() : String.Empty) + .Token("ContentType", content => content != null ? content.ContentItem.TypeDefinition.DisplayName : String.Empty) + .Chain("ContentType", "TypeDefinition", content => content != null ? content.ContentItem.TypeDefinition : null) + .Token("DisplayText", DisplayText) + .Chain("DisplayText", "Text", DisplayText) + .Token("DisplayUrl", DisplayUrl) + .Chain("DisplayUrl", "Url", DisplayUrl) + .Token("EditUrl", EditUrl) + .Chain("EditUrl", "Url", EditUrl) + .Token("Container", content => DisplayText(Container(content))) + .Chain("Container", "Content", Container) + .Token("Body", Body) + .Chain("Body", "Text", Body); if (context.Target == "Content") { var forContent = context.For("Content"); @@ -201,5 +234,36 @@ private string Body(IContent content) { return bodyPart.Text; } + + //returns Id:* Token + private static string ContentManagerGetToken(string token) { + string tokenPrefix, result; + int chainIndex, tokenLength; + + if (token.IndexOf(":") == -1) { + return null; + } + tokenPrefix = token.Substring(0, token.IndexOf(":")); + + chainIndex = token.IndexOf("."); + tokenLength = (tokenPrefix + ":").Length; + if (!token.StartsWith((tokenPrefix + ":"), StringComparison.OrdinalIgnoreCase) || chainIndex <= tokenLength) { + return null; + } + else if (chainIndex == 0) {// "." has not be found + result = token.Substring(tokenLength); + } + else { + result = token.Substring(0, chainIndex); + } + + // return the resulting id if it is a number, otherwise an empty string + if (int.TryParse(result.Substring(tokenPrefix.Length + 1), out var contentid)) { + return result; + } + else { + return ""; + } + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Web.config b/src/Orchard.Web/Modules/Orchard.Tokens/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Users/Handlers/UserPartHandler.cs b/src/Orchard.Web/Modules/Orchard.Users/Handlers/UserPartHandler.cs index 28e87eaf4e2..3e6d628f31d 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Handlers/UserPartHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Handlers/UserPartHandler.cs @@ -2,6 +2,7 @@ using Orchard.Data; using Orchard.ContentManagement.Handlers; using Orchard.Users.Models; +using System.Web.Routing; namespace Orchard.Users.Handlers { public class UserPartHandler : ContentHandler { @@ -16,6 +17,19 @@ protected override void GetItemMetadata(GetContentItemMetadataContext context) { if (part != null) { context.Metadata.Identity.Add("User.UserName", part.UserName); context.Metadata.DisplayText = part.UserName; + + // Configure routing metadata to make back-office experience more robust + context.Metadata.CreateRouteValues = new RouteValueDictionary { + {"Area", "Orchard.Users"}, + {"Controller", "Admin"}, + {"Action", "Create"} + }; + context.Metadata.EditorRouteValues = new RouteValueDictionary { + {"Area", "Orchard.Users"}, + {"Controller", "Admin"}, + {"Action", "Edit"}, + {"id", context.ContentItem.Id} + }; } } } diff --git a/src/Orchard.Web/Modules/Orchard.Users/Orchard.Users.csproj b/src/Orchard.Web/Modules/Orchard.Users/Orchard.Users.csproj index 2603ee618be..49f1c41d66f 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Orchard.Users.csproj +++ b/src/Orchard.Web/Modules/Orchard.Users/Orchard.Users.csproj @@ -315,4 +315,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Users/Services/UserService.cs b/src/Orchard.Web/Modules/Orchard.Users/Services/UserService.cs index 290e5923c34..30521327059 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Services/UserService.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Services/UserService.cs @@ -127,7 +127,11 @@ public IUser ValidateChallenge(string nonce) { var user = _membershipService.GetUser(username); if (user == null) return null; - + + if (user.As().EmailStatus == UserStatus.Approved) { + return null; + } + user.As().EmailStatus = UserStatus.Approved; return user; diff --git a/src/Orchard.Web/Modules/Orchard.Users/Web.config b/src/Orchard.Web/Modules/Orchard.Users/Web.config index cecb1033323..02e8598b73c 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Users/Web.config @@ -29,6 +29,7 @@ + @@ -40,24 +41,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -70,8 +71,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Warmup/Web.config b/src/Orchard.Web/Modules/Orchard.Warmup/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.Warmup/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Warmup/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Widgets/Layouts/Providers/WidgetElementHarvester.cs b/src/Orchard.Web/Modules/Orchard.Widgets/Layouts/Providers/WidgetElementHarvester.cs index e9f22463306..4249dec7471 100644 --- a/src/Orchard.Web/Modules/Orchard.Widgets/Layouts/Providers/WidgetElementHarvester.cs +++ b/src/Orchard.Web/Modules/Orchard.Widgets/Layouts/Providers/WidgetElementHarvester.cs @@ -13,6 +13,7 @@ using Orchard.Layouts.Framework.Elements; using Orchard.Layouts.Framework.Harvesters; using Orchard.Layouts.Helpers; +using Orchard.Layouts.Models; using Orchard.Mvc.Html; using Orchard.Security; using Orchard.Widgets.Layouts.Elements; @@ -47,11 +48,30 @@ public IEnumerable HarvestElements(HarvestElementsContext con Importing = ImportElement, StateBag = new Dictionary { { "ContentTypeName", contentTypeDefinition.Name } - } + }, + LayoutSaving = LayoutSaving }; }); } + private void LayoutSaving(ElementSavingContext context) { + // First, widget element container has to be stored. + var element = (Widget)context.Element; + if (element == null) { + return; + } + var widgetId = element.WidgetId; + var widget = _contentManager.Value.Get(widgetId.Value, VersionOptions.Latest); + if (widget == null) { + return; + } + + var commonPart = widget.As(); + if (commonPart != null) { + commonPart.Container = context.Content; + } + } + private void Displaying(ElementDisplayingContext context) { var contentTypeName = (string)context.Element.Descriptor.StateBag["ContentTypeName"]; var element = (Widget)context.Element; @@ -166,6 +186,18 @@ private void ImportElement(ImportElementContext context) { return; var widget = context.Session.GetItemFromSession(widgetIdentity); + + // A new widget needs to be created and saved. + // This is to avoid the fact the very same element ending up in multiple layouts, causing issues when e.g. deleting a LayoutWidget of a cloned ContentItem (which would delete the elements of multiple layouts). + // The new widget is needed only when the container of the original element is different from the container of the cloned element, to ensure doing it when cloning elements and avoid doing the same when importing content. + var cp = widget.As(); + if (cp != null) { + var lp = cp.Container.As(); + if (lp != null && lp.Id != context.Layout.Id) { + widget = _contentManager.Value.Clone(widget); + } + } + var element = (Widget)context.Element; element.WidgetId = widget != null ? widget.Id : default(int?); diff --git a/src/Orchard.Web/Modules/Orchard.Widgets/Views/WidgetPlacement.Zones.cshtml b/src/Orchard.Web/Modules/Orchard.Widgets/Views/WidgetPlacement.Zones.cshtml index 29563864962..5ee4ddb78a3 100644 --- a/src/Orchard.Web/Modules/Orchard.Widgets/Views/WidgetPlacement.Zones.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Widgets/Views/WidgetPlacement.Zones.cshtml @@ -1,8 +1,8 @@ -@using Orchard.ContentManagement; -@using Orchard.Core.Contents; -@using Orchard.Utility.Extensions; -@using Orchard.Widgets.Models; -@using Orchard.Localization.Models; +@using Orchard.ContentManagement +@using Orchard.Core.Contents +@using Orchard.Utility.Extensions +@using Orchard.Widgets.Models +@using Orchard.Localization.Models @{ Style.Require("WidgetsAdmin"); IEnumerable widgets = Model.Widgets; diff --git a/src/Orchard.Web/Modules/Orchard.Widgets/Web.config b/src/Orchard.Web/Modules/Orchard.Widgets/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.Widgets/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Widgets/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Workflows/Orchard.Workflows.csproj b/src/Orchard.Web/Modules/Orchard.Workflows/Orchard.Workflows.csproj index 71e5a7e0b99..cea54c19a4a 100644 --- a/src/Orchard.Web/Modules/Orchard.Workflows/Orchard.Workflows.csproj +++ b/src/Orchard.Web/Modules/Orchard.Workflows/Orchard.Workflows.csproj @@ -70,7 +70,7 @@ 3.5 - + @@ -301,4 +301,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Workflows/Web.config b/src/Orchard.Web/Modules/Orchard.Workflows/Web.config index 854be8b67fa..0df49e40c1c 100644 --- a/src/Orchard.Web/Modules/Orchard.Workflows/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Workflows/Web.config @@ -29,6 +29,7 @@ + @@ -39,24 +40,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +70,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Orchard.Workflows/packages.config b/src/Orchard.Web/Modules/Orchard.Workflows/packages.config index 2ae22b193cd..51c3aaef7f0 100644 --- a/src/Orchard.Web/Modules/Orchard.Workflows/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Workflows/packages.config @@ -6,4 +6,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.jQuery/Web.config b/src/Orchard.Web/Modules/Orchard.jQuery/Web.config index 854be8b67fa..933fe9ba185 100644 --- a/src/Orchard.Web/Modules/Orchard.jQuery/Web.config +++ b/src/Orchard.Web/Modules/Orchard.jQuery/Web.config @@ -39,24 +39,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + @@ -69,8 +69,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/SysCache/SysCache.csproj b/src/Orchard.Web/Modules/SysCache/SysCache.csproj index 1269a6990ca..ea061c1e5fc 100644 --- a/src/Orchard.Web/Modules/SysCache/SysCache.csproj +++ b/src/Orchard.Web/Modules/SysCache/SysCache.csproj @@ -152,4 +152,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/SysCache/Web.config b/src/Orchard.Web/Modules/SysCache/Web.config index 7a21a391b4f..804fac07aba 100644 --- a/src/Orchard.Web/Modules/SysCache/Web.config +++ b/src/Orchard.Web/Modules/SysCache/Web.config @@ -33,24 +33,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - + + + diff --git a/src/Orchard.Web/Modules/SysCache/packages.config b/src/Orchard.Web/Modules/SysCache/packages.config index a926d5aaf2c..af2d30f46ba 100644 --- a/src/Orchard.Web/Modules/SysCache/packages.config +++ b/src/Orchard.Web/Modules/SysCache/packages.config @@ -6,4 +6,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/TinyMce/Scripts/orchard-tinymce.js b/src/Orchard.Web/Modules/TinyMce/Scripts/orchard-tinymce.js index 0640d723db9..a64fd45a1ac 100644 --- a/src/Orchard.Web/Modules/TinyMce/Scripts/orchard-tinymce.js +++ b/src/Orchard.Web/Modules/TinyMce/Scripts/orchard-tinymce.js @@ -1,4 +1,6 @@ var mediaPlugins = ""; +var contentPickerPlugins = ""; +var contentPickerButtons = ""; if (mediaPickerEnabled) { mediaPlugins += " mediapicker"; @@ -8,14 +10,19 @@ if (mediaLibraryEnabled) { mediaPlugins += " medialibrary"; } +if (contenPickerEnabled && tokensHtmlFilterEnabled) { + contentPickerPlugins += " orchardcontentlinks" + contentPickerButtons += "orchardlink" +} + tinyMCE.init({ selector: "textarea.tinymce", theme: "modern", schema: "html5", plugins: [ - "advlist, anchor, autolink, autoresize, charmap, code, colorpicker, contextmenu, directionality, emoticons, fullscreen, hr, image, insertdatetime, link, lists, media, nonbreaking, pagebreak, paste, preview, print, searchreplace, table, template, textcolor, textpattern, visualblocks, visualchars, wordcount" + mediaPlugins + "advlist, anchor, autolink, autoresize, charmap, code, colorpicker, contextmenu, directionality, emoticons, fullscreen, hr, image, insertdatetime, link, lists, media, nonbreaking, pagebreak, paste, preview, print, searchreplace, table, template, textcolor, textpattern, visualblocks, visualchars, wordcount, htmlsnippets" + (contentPickerPlugins != "" ? ", " + contentPickerPlugins : "") + (mediaPlugins != "" ? ", " + mediaPlugins : "") ], - toolbar: "undo redo cut copy paste | bold italic | bullist numlist outdent indent formatselect | alignleft aligncenter alignright alignjustify ltr rtl | " + mediaPlugins + " link unlink charmap | code fullscreen", + toolbar: "undo redo cut copy paste | bold italic | bullist numlist outdent indent formatselect | alignleft aligncenter alignright alignjustify ltr rtl | " + mediaPlugins + " link " + contentPickerButtons + " unlink charmap | code htmlsnippetsbutton fullscreen", convert_urls: false, valid_elements: "*[*]", // Shouldn't be needed due to the valid_elements setting, but TinyMCE would strip script.src without it. @@ -27,7 +34,7 @@ tinyMCE.init({ auto_focus: autofocus, directionality: directionality, setup: function (editor) { - $(document).bind("localization.ui.directionalitychanged", function(event, directionality) { + $(document).bind("localization.ui.directionalitychanged", function (event, directionality) { editor.getBody().dir = directionality; }); diff --git a/src/Orchard.Web/Modules/TinyMce/Scripts/plugins/htmlsnippets/plugin.js b/src/Orchard.Web/Modules/TinyMce/Scripts/plugins/htmlsnippets/plugin.js new file mode 100644 index 00000000000..5a589dd7953 --- /dev/null +++ b/src/Orchard.Web/Modules/TinyMce/Scripts/plugins/htmlsnippets/plugin.js @@ -0,0 +1,42 @@ + +tinymce.PluginManager.add('htmlsnippets', function(editor, url) { + var htmlSnippetAction = function() { + // Open window + var modalWindow = editor.windowManager.open({ + title: 'Insert/edit HTML snippets', + body: [ + {type: 'textbox', value: editor.selection.getContent(), multiline: true, name: 'html_snippet', label: 'HTML Snippet', minHeight:350} + ], + height: 400, + width: 600, + onsubmit: function(e) { + // Insert content when the window form is submitted + editor.insertContent(e.data.html_snippet); + } + }); + } + + // Add a button that opens a window + editor.addButton('htmlsnippetsbutton', { + image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QAEABHAPK/xSSIAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAvElEQVRIx+2VsRHCMAxFH3AwAR075CjSpGOfLEU6nAKmoIICJohHYANoVPjAji0nNLn8OxeSvny2vmTDDCUOQOfYb1mptpU9grDKDX12N20Nvq88OH+ZkLQGDFA7vho4SWwQdkADPIHS8ZfiOwonC1s5+R2oPPFKYka46hpegCtQ9PD3wA0452qwiXBWwlnklqhNKFGrKVFI5EdA5EYrsm8OQm1qPG0anaPRB216eI3wXNvYh2P/+eHM+MEHpr9Js1lOQvUAAAAASUVORK5CYII=', + tooltip: 'Html snippet', + onclick: htmlSnippetAction + }); + + // Adds a menu item to the tools menu + editor.addMenuItem('HTMLsnippetmenuitem ', { + text: 'Html snippet', + image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QAEABHAPK/xSSIAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAvElEQVRIx+2VsRHCMAxFH3AwAR075CjSpGOfLEU6nAKmoIICJohHYANoVPjAji0nNLn8OxeSvny2vmTDDCUOQOfYb1mptpU9grDKDX12N20Nvq88OH+ZkLQGDFA7vho4SWwQdkADPIHS8ZfiOwonC1s5+R2oPPFKYka46hpegCtQ9PD3wA0452qwiXBWwlnklqhNKFGrKVFI5EdA5EYrsm8OQm1qPG0anaPRB216eI3wXNvYh2P/+eHM+MEHpr9Js1lOQvUAAAAASUVORK5CYII=', + context: 'insert', + onclick: htmlSnippetAction + }); + + return { + getMetadata: function () { + return { + name: "Html snippets plugin" + //url: "http://exampleplugindocsurl.com" + }; + } + }; +}); diff --git a/src/Orchard.Web/Modules/TinyMce/Scripts/plugins/htmlsnippets/plugin.min.js b/src/Orchard.Web/Modules/TinyMce/Scripts/plugins/htmlsnippets/plugin.min.js new file mode 100644 index 00000000000..ea34e83dd02 --- /dev/null +++ b/src/Orchard.Web/Modules/TinyMce/Scripts/plugins/htmlsnippets/plugin.min.js @@ -0,0 +1 @@ +tinymce.PluginManager.add("htmlsnippets",function(A,t){var n=function(){A.windowManager.open({title:"Insert/edit HTML snippets",body:[{type:"textbox",value:A.selection.getContent(),multiline:!0,name:"html_snippet",label:"HTML Snippet",minHeight:350}],height:400,width:600,onsubmit:function(t){A.insertContent(t.data.html_snippet)}})};return A.addButton("htmlsnippetsbutton",{image:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QAEABHAPK/xSSIAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAvElEQVRIx+2VsRHCMAxFH3AwAR075CjSpGOfLEU6nAKmoIICJohHYANoVPjAji0nNLn8OxeSvny2vmTDDCUOQOfYb1mptpU9grDKDX12N20Nvq88OH+ZkLQGDFA7vho4SWwQdkADPIHS8ZfiOwonC1s5+R2oPPFKYka46hpegCtQ9PD3wA0452qwiXBWwlnklqhNKFGrKVFI5EdA5EYrsm8OQm1qPG0anaPRB216eI3wXNvYh2P/+eHM+MEHpr9Js1lOQvUAAAAASUVORK5CYII=",tooltip:"Html snippet",onclick:n}),A.addMenuItem("HTMLsnippetmenuitem ",{text:"Html snippet",image:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QAEABHAPK/xSSIAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAvElEQVRIx+2VsRHCMAxFH3AwAR075CjSpGOfLEU6nAKmoIICJohHYANoVPjAji0nNLn8OxeSvny2vmTDDCUOQOfYb1mptpU9grDKDX12N20Nvq88OH+ZkLQGDFA7vho4SWwQdkADPIHS8ZfiOwonC1s5+R2oPPFKYka46hpegCtQ9PD3wA0452qwiXBWwlnklqhNKFGrKVFI5EdA5EYrsm8OQm1qPG0anaPRB216eI3wXNvYh2P/+eHM+MEHpr9Js1lOQvUAAAAASUVORK5CYII=",context:"insert",onclick:n}),{getMetadata:function(){return{name:"Html snippets plugin"}}}}); \ No newline at end of file diff --git a/src/Orchard.Web/Modules/TinyMce/Scripts/plugins/medialibrary/plugin.js b/src/Orchard.Web/Modules/TinyMce/Scripts/plugins/medialibrary/plugin.js index 26cf7fa8f8f..5a468ca7afa 100644 --- a/src/Orchard.Web/Modules/TinyMce/Scripts/plugins/medialibrary/plugin.js +++ b/src/Orchard.Web/Modules/TinyMce/Scripts/plugins/medialibrary/plugin.js @@ -17,9 +17,7 @@ // Register the command so that it can be invoked by using tinyMCE.activeEditor.execCommand('mceMediaPicker'); ed.addCommand('mceMediaLibrary', function () { ed.focus(); - var adminIndex = location.href.toLowerCase().indexOf("/admin/"); - if (adminIndex === -1) return; - var url = location.href.substr(0, adminIndex) + "/Admin/Orchard.MediaLibrary?dialog=true"; + var url = baseOrchardPath + "Admin/Orchard.MediaLibrary?dialog=true"; $.colorbox({ href: url, iframe: true, @@ -41,7 +39,7 @@ var newContent = ''; for (var i = 0; i < selectedData.length; i++) { - var renderMedia = location.href.substr(0, adminIndex) + "/Admin/Orchard.MediaLibrary/MediaItem/" + selectedData[i].id + "?displayType=Raw"; + var renderMedia = baseOrchardPath + "/Admin/Orchard.MediaLibrary/MediaItem/" + selectedData[i].id + "?displayType=Raw"; $.ajax({ async: false, type: 'GET', diff --git a/src/Orchard.Web/Modules/TinyMce/Scripts/plugins/medialibrary/plugin.min.js b/src/Orchard.Web/Modules/TinyMce/Scripts/plugins/medialibrary/plugin.min.js index 96ed4b31c98..37ae3eab71b 100644 --- a/src/Orchard.Web/Modules/TinyMce/Scripts/plugins/medialibrary/plugin.min.js +++ b/src/Orchard.Web/Modules/TinyMce/Scripts/plugins/medialibrary/plugin.min.js @@ -1,4 +1 @@ -(function(){tinymce.create("tinymce.plugins.Orchard.MediaLibrary",{init:function(n){n.addCommand("mceMediaLibrary",function(){var t,i;(n.focus(),t=location.href.toLowerCase().indexOf("/admin/"),t!==-1)&&(i=location.href.substr(0,t)+"/Admin/Orchard.MediaLibrary?dialog=true",$.colorbox({href:i,iframe:!0,reposition:!0,width:"90%",height:"90%",onLoad:function(){$("html, body").css("overflow","hidden")},onClosed:function(){var n,r,i,u;if($("html, body").css("overflow",""),n=$.colorbox.selectedData,n!=null){for(r="",i=0;i" + textLink + ""); + + }; + $[callbackName].data = data; + + // Open content picker window + var baseUrl = baseOrchardPath; + + // remove trailing slash if any + if (baseUrl.slice(-1) == '/') + baseUrl = baseUrl.substr(0, baseUrl.length - 1); + var url = baseUrl + "/Admin/Orchard.ContentPicker?"; + url += "callback=" + callbackName + "&" + (new Date() - 0); + if ($("#" + editor.id).data("content-types")) { + url += "&types=" + $("#" + editor.id).data("content-types"); + } + var w = window.open(url, "_blank", data.windowFeatures || "width=685,height=700,status=no,toolbar=no,location=no,menubar=no,resizable=no,scrollbars=yes"); + } + + // Add a button that opens a window + editor.addButton('orchardlink', { + image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsSAAALEgHS3X78AAABb0lEQVRIibWW223CQBBFDxEFUAIdJNHsf6CCkApiKgBXAFSAUgFJBdCB4X9HogSX4A6Sjx0rK8cGY5P7sw9Z93h3HvYAk4jbAk/cpgLYqPpz0wODCJDZ9NTSfBVBpk2QKuCk6tdt3EXcN5BGoFrIQ8u3bdIZeAZyIBNxf664LwBVnwPTJkhvgEGKJsiwp/dCxE2i9RFYAlsD9gIcgRHwUtkv4kVngKqf1u2LuHUMvUsMLunfAVevSMQtCUf+UvWHWwEXTyDidoSMGAF7EZfcDWDmCTC3gM6BnYgb9wZYoSSEXlP2l3LsDCiAQzTPgXd+KzMDzqr+2Amg6t+AmXXViUHGBs0MWJv7rQB25yszWpn5xsYjoR0XVYNrGkbmCSGQr4SsyYG8qWLbqjxBAqSq/hP4MNDYQL1UFloBPEbzPeEENxdWEyAl5PiIEOCcjndeVfxNngELM08NdOtfBlgnLWM3qHvC8n7bwbzUWdWnAD+rk38HDdeC5gAAAABJRU5ErkJggg==', + tooltip: 'Content link', + onclick: contentPickerAction + }); + + // Adds a menu item to the tools menu + editor.addMenuItem('orchardlink ', { + text: 'content link', + image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsSAAALEgHS3X78AAABb0lEQVRIibWW223CQBBFDxEFUAIdJNHsf6CCkApiKgBXAFSAUgFJBdCB4X9HogSX4A6Sjx0rK8cGY5P7sw9Z93h3HvYAk4jbAk/cpgLYqPpz0wODCJDZ9NTSfBVBpk2QKuCk6tdt3EXcN5BGoFrIQ8u3bdIZeAZyIBNxf664LwBVnwPTJkhvgEGKJsiwp/dCxE2i9RFYAlsD9gIcgRHwUtkv4kVngKqf1u2LuHUMvUsMLunfAVevSMQtCUf+UvWHWwEXTyDidoSMGAF7EZfcDWDmCTC3gM6BnYgb9wZYoSSEXlP2l3LsDCiAQzTPgXd+KzMDzqr+2Amg6t+AmXXViUHGBs0MWJv7rQB25yszWpn5xsYjoR0XVYNrGkbmCSGQr4SsyYG8qWLbqjxBAqSq/hP4MNDYQL1UFloBPEbzPeEENxdWEyAl5PiIEOCcjndeVfxNngELM08NdOtfBlgnLWM3qHvC8n7bwbzUWdWnAD+rk38HDdeC5gAAAABJRU5ErkJggg==', + context: 'insert', + onclick: contentPickerAction + }); + + return { + getMetadata: function () { + return { + name: "Orchard content link plugin" + }; + } + }; +}); diff --git a/src/Orchard.Web/Modules/TinyMce/Scripts/plugins/orchardcontentlinks/plugin.min.js b/src/Orchard.Web/Modules/TinyMce/Scripts/plugins/orchardcontentlinks/plugin.min.js new file mode 100644 index 00000000000..f69818d12d9 --- /dev/null +++ b/src/Orchard.Web/Modules/TinyMce/Scripts/plugins/orchardcontentlinks/plugin.min.js @@ -0,0 +1 @@ +tinymce.PluginManager.add("orchardcontentlinks", function (A, n) { var t = function () { var n = {}, t = "_contentpicker_" + new Date().getTime(); n.callbackName = t, $[t] = function (n) { delete $[t]; var e = A.selection.getContent(); e && "" != e || (e = n.displayText), A.insertContent('' + e + "") }, $[t].data = n; var e = baseOrchardPath; "/" == e.slice(-1) && (e = e.substr(0, e.length - 1)); var g = e + "/Admin/Orchard.ContentPicker?"; g += "callback=" + t + "&" + (new Date - 0), $("#" + A.id).data("content-types") && (g += "&types=" + $("#" + A.id).data("content-types")), window.open(g, "_blank", n.windowFeatures || "width=685,height=700,status=no,toolbar=no,location=no,menubar=no,resizable=no,scrollbars=yes") }; return A.addButton("orchardlink", { image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsSAAALEgHS3X78AAABb0lEQVRIibWW223CQBBFDxEFUAIdJNHsf6CCkApiKgBXAFSAUgFJBdCB4X9HogSX4A6Sjx0rK8cGY5P7sw9Z93h3HvYAk4jbAk/cpgLYqPpz0wODCJDZ9NTSfBVBpk2QKuCk6tdt3EXcN5BGoFrIQ8u3bdIZeAZyIBNxf664LwBVnwPTJkhvgEGKJsiwp/dCxE2i9RFYAlsD9gIcgRHwUtkv4kVngKqf1u2LuHUMvUsMLunfAVevSMQtCUf+UvWHWwEXTyDidoSMGAF7EZfcDWDmCTC3gM6BnYgb9wZYoSSEXlP2l3LsDCiAQzTPgXd+KzMDzqr+2Amg6t+AmXXViUHGBs0MWJv7rQB25yszWpn5xsYjoR0XVYNrGkbmCSGQr4SsyYG8qWLbqjxBAqSq/hP4MNDYQL1UFloBPEbzPeEENxdWEyAl5PiIEOCcjndeVfxNngELM08NdOtfBlgnLWM3qHvC8n7bwbzUWdWnAD+rk38HDdeC5gAAAABJRU5ErkJggg==", tooltip: "Content link", onclick: t }), A.addMenuItem("orchardlink ", { text: "content link", image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsSAAALEgHS3X78AAABb0lEQVRIibWW223CQBBFDxEFUAIdJNHsf6CCkApiKgBXAFSAUgFJBdCB4X9HogSX4A6Sjx0rK8cGY5P7sw9Z93h3HvYAk4jbAk/cpgLYqPpz0wODCJDZ9NTSfBVBpk2QKuCk6tdt3EXcN5BGoFrIQ8u3bdIZeAZyIBNxf664LwBVnwPTJkhvgEGKJsiwp/dCxE2i9RFYAlsD9gIcgRHwUtkv4kVngKqf1u2LuHUMvUsMLunfAVevSMQtCUf+UvWHWwEXTyDidoSMGAF7EZfcDWDmCTC3gM6BnYgb9wZYoSSEXlP2l3LsDCiAQzTPgXd+KzMDzqr+2Amg6t+AmXXViUHGBs0MWJv7rQB25yszWpn5xsYjoR0XVYNrGkbmCSGQr4SsyYG8qWLbqjxBAqSq/hP4MNDYQL1UFloBPEbzPeEENxdWEyAl5PiIEOCcjndeVfxNngELM08NdOtfBlgnLWM3qHvC8n7bwbzUWdWnAD+rk38HDdeC5gAAAABJRU5ErkJggg==", context: "insert", onclick: t }), { getMetadata: function () { return { name: "Orchard content link plugin" } } } }); \ No newline at end of file diff --git a/src/Orchard.Web/Modules/TinyMce/Settings/ContentLinksSettings.cs b/src/Orchard.Web/Modules/TinyMce/Settings/ContentLinksSettings.cs new file mode 100644 index 00000000000..13d97959cc4 --- /dev/null +++ b/src/Orchard.Web/Modules/TinyMce/Settings/ContentLinksSettings.cs @@ -0,0 +1,5 @@ +namespace TinyMce.Settings { + public class ContentLinksSettings { + public string DisplayedContentTypes { get; set; } + } +} diff --git a/src/Orchard.Web/Modules/TinyMce/Settings/EditorEvents.cs b/src/Orchard.Web/Modules/TinyMce/Settings/EditorEvents.cs new file mode 100644 index 00000000000..dc9e789470a --- /dev/null +++ b/src/Orchard.Web/Modules/TinyMce/Settings/EditorEvents.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Orchard.ContentManagement; +using Orchard.ContentManagement.MetaData; +using Orchard.ContentManagement.MetaData.Builders; +using Orchard.ContentManagement.MetaData.Models; +using Orchard.ContentManagement.ViewModels; +using Orchard.Environment.Descriptor.Models; + +namespace TinyMce.Settings { + public class EditorEvents : ContentDefinitionEditorEventsBase { + + private string[] _htmlParts = new string[] { "BodyPart", "LayoutPart" }; + private string[] _htmlFields = new string[] { "TextField" }; + private bool _contentLinksDependenciesEnabled = false; + + public EditorEvents(ShellDescriptor shellDescriptor) { + var contenPickerEnabled = shellDescriptor.Features.Any(x => x.Name == "Orchard.ContentPicker") ? true : false; + var tokensHtmlFilterEnabled = shellDescriptor.Features.Any(x => x.Name == "Orchard.Tokens.HtmlFilter") ? true : false; + _contentLinksDependenciesEnabled = contenPickerEnabled && tokensHtmlFilterEnabled; + } + + public override IEnumerable PartFieldEditor(ContentPartFieldDefinition definition) { + if (!_contentLinksDependenciesEnabled || !_htmlFields.Any(x => x.Equals(definition.FieldDefinition.Name, StringComparison.InvariantCultureIgnoreCase))) + yield break; + var model = definition.Settings.GetModel(); + yield return DefinitionTemplate(model); + } + + public override IEnumerable PartFieldEditorUpdate(ContentPartFieldDefinitionBuilder builder, IUpdateModel updateModel) { + if (!_contentLinksDependenciesEnabled || !_htmlFields.Any(x => x.Equals(builder.FieldType, StringComparison.InvariantCultureIgnoreCase))) + yield break; + + var model = new ContentLinksSettings(); + updateModel.TryUpdateModel(model, "ContentLinksSettings", null, null); + builder.WithSetting("ContentLinksSettings.DisplayedContentTypes", model.DisplayedContentTypes); + + yield return DefinitionTemplate(model); + } + + public override IEnumerable TypePartEditor(ContentTypePartDefinition definition) { + if (!_contentLinksDependenciesEnabled || !_htmlParts.Any(x => x.Equals(definition.PartDefinition.Name, StringComparison.InvariantCultureIgnoreCase))) + yield break; + var model = definition.Settings.GetModel(); + yield return DefinitionTemplate(model); + } + + + public override IEnumerable TypePartEditorUpdate(ContentTypePartDefinitionBuilder builder, IUpdateModel updateModel) { + if (!_contentLinksDependenciesEnabled || !_htmlParts.Any(x => x.Equals(builder.Name, StringComparison.InvariantCultureIgnoreCase))) + yield break; + var model = new ContentLinksSettings(); + updateModel.TryUpdateModel(model, "ContentLinksSettings", null, null); + builder.WithSetting("ContentLinksSettings.DisplayedContentTypes", model.DisplayedContentTypes); + yield return DefinitionTemplate(model); + } + } +} diff --git a/src/Orchard.Web/Modules/TinyMce/TinyMce.csproj b/src/Orchard.Web/Modules/TinyMce/TinyMce.csproj index e0ce2db4bb4..9b41f3bf2dd 100644 --- a/src/Orchard.Web/Modules/TinyMce/TinyMce.csproj +++ b/src/Orchard.Web/Modules/TinyMce/TinyMce.csproj @@ -220,6 +220,8 @@ + + @@ -248,6 +250,8 @@ + + @@ -315,6 +319,8 @@ + + @@ -377,7 +383,9 @@ + + 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) diff --git a/src/Orchard.Web/Modules/TinyMce/Views/Body-Html.Editor.cshtml b/src/Orchard.Web/Modules/TinyMce/Views/Body-Html.Editor.cshtml index 345f8e06976..3010cb89584 100644 --- a/src/Orchard.Web/Modules/TinyMce/Views/Body-Html.Editor.cshtml +++ b/src/Orchard.Web/Modules/TinyMce/Views/Body-Html.Editor.cshtml @@ -1,18 +1,42 @@ @using Orchard.ContentManagement +@using Orchard.Environment.Configuration @using Orchard.Environment.Descriptor.Models @using Orchard.Localization - +@using Orchard.Mvc.Extensions +@using TinyMce.Settings @{ var propertyName = Model.PropertyName != null ? (string)Model.PropertyName : "Text"; var shellDescriptor = WorkContext.Resolve(); + var urlPrefix = WorkContext.Resolve().RequestUrlPrefix; + if (!string.IsNullOrWhiteSpace(urlPrefix)) { + urlPrefix += "/"; + } + var contentTypes = ""; + if (Model.Field != null) { + var settings = Model.Field.PartFieldDefinition.Settings.GetModel(); + if (settings != null) { + contentTypes = settings.DisplayedContentTypes; + } + } + else if (Model.Part != null) { + var settings = Model.Part.TypePartDefinition.Settings.GetModel(); + if (settings != null) { + contentTypes = settings.DisplayedContentTypes; + } + } + + } @{ @@ -27,5 +51,6 @@ { "class", "html tinymce" }, { "data-mediapicker-uploadpath", Model.AddMediaPath }, { "data-mediapicker-title", T("Insert/Update Media") }, + { "data-content-types", contentTypes }, { "style", "width:100%" } }) diff --git a/src/Orchard.Web/Modules/TinyMce/Views/DefinitionTemplates/ContentLinksSettings.cshtml b/src/Orchard.Web/Modules/TinyMce/Views/DefinitionTemplates/ContentLinksSettings.cshtml new file mode 100644 index 00000000000..1d9b786b900 --- /dev/null +++ b/src/Orchard.Web/Modules/TinyMce/Views/DefinitionTemplates/ContentLinksSettings.cshtml @@ -0,0 +1,8 @@ +@model TinyMce.Settings.ContentLinksSettings +
+
+ + @Html.TextBoxFor(m => m.DisplayedContentTypes) + @T("A comma separated value of all the content types or content parts to be linkable contents.") +
+
diff --git a/src/Orchard.Web/Modules/TinyMce/Web.config b/src/Orchard.Web/Modules/TinyMce/Web.config index 091ef6f4590..ae6866773ad 100644 --- a/src/Orchard.Web/Modules/TinyMce/Web.config +++ b/src/Orchard.Web/Modules/TinyMce/Web.config @@ -38,38 +38,38 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - + + + diff --git a/src/Orchard.Web/Modules/Upgrade/Upgrade.csproj b/src/Orchard.Web/Modules/Upgrade/Upgrade.csproj index 7b0d6bb7d62..81604ab6654 100644 --- a/src/Orchard.Web/Modules/Upgrade/Upgrade.csproj +++ b/src/Orchard.Web/Modules/Upgrade/Upgrade.csproj @@ -84,7 +84,6 @@ 3.5 - ..\..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.7\lib\net45\System.Net.Http.Formatting.dll diff --git a/src/Orchard.Web/Modules/Upgrade/Web.config b/src/Orchard.Web/Modules/Upgrade/Web.config index b7cc5615636..3c834e8b89e 100644 --- a/src/Orchard.Web/Modules/Upgrade/Web.config +++ b/src/Orchard.Web/Modules/Upgrade/Web.config @@ -41,24 +41,36 @@ - - - - + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -71,8 +83,8 @@ - - + + diff --git a/src/Orchard.Web/Modules/Upgrade/packages.config b/src/Orchard.Web/Modules/Upgrade/packages.config index c9692138194..5e7dacf19a0 100644 --- a/src/Orchard.Web/Modules/Upgrade/packages.config +++ b/src/Orchard.Web/Modules/Upgrade/packages.config @@ -13,4 +13,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Orchard.Web.csproj b/src/Orchard.Web/Orchard.Web.csproj index c61e189ac7b..6d6637cbc1f 100644 --- a/src/Orchard.Web/Orchard.Web.csproj +++ b/src/Orchard.Web/Orchard.Web.csproj @@ -59,7 +59,6 @@ ..\packages\Glimpse.AspNet.1.9.2\lib\net45\Glimpse.AspNet.dll - True ..\packages\Glimpse.1.8.6\lib\net45\Glimpse.Core.dll @@ -67,7 +66,6 @@ ..\packages\Glimpse.Mvc5.1.5.3\lib\net45\Glimpse.Mvc5.dll - True ..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.2.0.1\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll diff --git a/src/Orchard.Web/Themes/TheAdmin/Views/LocalMenu.cshtml b/src/Orchard.Web/Themes/TheAdmin/Views/LocalMenu.cshtml index 87dc8244d59..efdc9129bbf 100644 --- a/src/Orchard.Web/Themes/TheAdmin/Views/LocalMenu.cshtml +++ b/src/Orchard.Web/Themes/TheAdmin/Views/LocalMenu.cshtml @@ -6,8 +6,9 @@ Model.Attributes.Add("role", "local-navigation"); var tag = Tag(Model, "ul"); } -@tag.StartElement - @foreach(var firstLevelMenuItem in Model) { +@if (Model.Items!=null && Model.Items.Count > 0) { + @tag.StartElement + foreach (var firstLevelMenuItem in Model) { if (firstLevelMenuItem.LocalNav) { string sectionHeaderText = firstLevelMenuItem.Text.Text; @@ -34,8 +35,9 @@ firstLevelMenuItem.Classes.Add("local-section-" + sectionHeaderText.HtmlClassify()); var firstLevelTag = Tag(firstLevelMenuItem, "li"); @firstLevelTag.StartElement - @sectionHeaderMarkup - @firstLevelTag.EndElement + @sectionHeaderMarkup + @firstLevelTag.EndElement } } -@tag.EndElement + @tag.EndElement +} \ No newline at end of file diff --git a/src/Orchard.Web/Themes/Web.config b/src/Orchard.Web/Themes/Web.config index c09bf5a019a..391a345a798 100644 --- a/src/Orchard.Web/Themes/Web.config +++ b/src/Orchard.Web/Themes/Web.config @@ -62,38 +62,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + diff --git a/src/Orchard.Web/Web.config b/src/Orchard.Web/Web.config index deb52a5ccf0..42ba38c42e4 100644 --- a/src/Orchard.Web/Web.config +++ b/src/Orchard.Web/Web.config @@ -97,7 +97,6 @@ - @@ -230,7 +229,6 @@ - diff --git a/src/Orchard.sln b/src/Orchard.sln index 8da00a6d7f9..6b0c5dc44ed 100644 --- a/src/Orchard.sln +++ b/src/Orchard.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.1738 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33815.320 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5}" EndProject @@ -285,8 +285,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Conditions", "Orcha EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Resources", "Orchard.Web\Modules\Orchard.Resources\Orchard.Resources.csproj", "{D4E8F7C8-2DB2-4C50-A422-DA1DF1E3CC73}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Azure.Tests", "Orchard.Azure.Tests\Orchard.Azure.Tests.csproj", "{1CC62F45-E6FF-43D5-84BF-509A1085D994}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.OpenId", "Orchard.Web\Modules\Orchard.OpenId\Orchard.OpenId.csproj", "{42E217C1-E163-4B6B-9E8F-42BEE21B6896}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Glimpse", "Orchard.Web\Modules\Orchard.Glimpse\Orchard.Glimpse.csproj", "{71E17466-D937-49D7-8C7D-77CCBAB8CCF4}" @@ -306,6 +304,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{4C95F27D-A872-481F-A9AF-851DB178C186}" ProjectSection(SolutionItems) = preProject ..\.github\workflows\build-crowdin-translation-packages.yml = ..\.github\workflows\build-crowdin-translation-packages.yml + ..\.github\workflows\compile.yml = ..\.github\workflows\compile.yml EndProjectSection EndProject Global @@ -1134,16 +1133,6 @@ Global {D4E8F7C8-2DB2-4C50-A422-DA1DF1E3CC73}.FxCop|Any CPU.ActiveCfg = Release|Any CPU {D4E8F7C8-2DB2-4C50-A422-DA1DF1E3CC73}.Release|Any CPU.ActiveCfg = Release|Any CPU {D4E8F7C8-2DB2-4C50-A422-DA1DF1E3CC73}.Release|Any CPU.Build.0 = Release|Any CPU - {1CC62F45-E6FF-43D5-84BF-509A1085D994}.CodeCoverage|Any CPU.ActiveCfg = Release|Any CPU - {1CC62F45-E6FF-43D5-84BF-509A1085D994}.CodeCoverage|Any CPU.Build.0 = Release|Any CPU - {1CC62F45-E6FF-43D5-84BF-509A1085D994}.Coverage|Any CPU.ActiveCfg = Release|Any CPU - {1CC62F45-E6FF-43D5-84BF-509A1085D994}.Coverage|Any CPU.Build.0 = Release|Any CPU - {1CC62F45-E6FF-43D5-84BF-509A1085D994}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1CC62F45-E6FF-43D5-84BF-509A1085D994}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1CC62F45-E6FF-43D5-84BF-509A1085D994}.FxCop|Any CPU.ActiveCfg = Release|Any CPU - {1CC62F45-E6FF-43D5-84BF-509A1085D994}.FxCop|Any CPU.Build.0 = Release|Any CPU - {1CC62F45-E6FF-43D5-84BF-509A1085D994}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1CC62F45-E6FF-43D5-84BF-509A1085D994}.Release|Any CPU.Build.0 = Release|Any CPU {42E217C1-E163-4B6B-9E8F-42BEE21B6896}.CodeCoverage|Any CPU.ActiveCfg = Release|Any CPU {42E217C1-E163-4B6B-9E8F-42BEE21B6896}.Coverage|Any CPU.ActiveCfg = Release|Any CPU {42E217C1-E163-4B6B-9E8F-42BEE21B6896}.Debug|Any CPU.ActiveCfg = Debug|Any CPU @@ -1278,7 +1267,6 @@ Global {90EBEE36-B5CD-42A8-A21B-76270E2C5D24} = {DF3909B0-1DDD-4D8A-9919-56FC438E25E2} {98251EAE-A41B-47B2-AA91-E28B8482DA70} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5} {D4E8F7C8-2DB2-4C50-A422-DA1DF1E3CC73} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5} - {1CC62F45-E6FF-43D5-84BF-509A1085D994} = {74E681ED-FECC-4034-B9BD-01B0BB1BDECA} {42E217C1-E163-4B6B-9E8F-42BEE21B6896} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5} {71E17466-D937-49D7-8C7D-77CCBAB8CCF4} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5} {A17BE797-D4AF-4CB4-A9FD-AE7BA09A95BD} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5} @@ -1288,7 +1276,7 @@ Global {4C95F27D-A872-481F-A9AF-851DB178C186} = {06A32C3C-10A2-472E-B725-5AF102E92C6F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - EnterpriseLibraryConfigurationToolBinariesPath = packages\TransientFaultHandling.Core.5.1.1209.1\lib\NET4 SolutionGuid = {3585D970-275B-4363-9F61-CD37CFC9DCD3} + EnterpriseLibraryConfigurationToolBinariesPath = packages\TransientFaultHandling.Core.5.1.1209.1\lib\NET4 EndGlobalSection EndGlobal diff --git a/src/Orchard/ContentManagement/Handlers/TemplateFilterForPart.cs b/src/Orchard/ContentManagement/Handlers/TemplateFilterForPart.cs index 29074ab7172..6b92ef897be 100644 --- a/src/Orchard/ContentManagement/Handlers/TemplateFilterForPart.cs +++ b/src/Orchard/ContentManagement/Handlers/TemplateFilterForPart.cs @@ -40,8 +40,10 @@ protected override void BuildEditorShape(BuildEditorContext context, ContentPart return; var templatePart = part.As(); - var templateShape = context.New.EditorTemplate(TemplateName: _templateName, Model: templatePart, Prefix: _prefix); - context.Shape.Zones[_location].Add(templateShape, _position); + if (templatePart != null) { + var templateShape = context.New.EditorTemplate(TemplateName: _templateName, Model: templatePart, Prefix: _prefix); + context.Shape.Zones[_location].Add(templateShape, _position); + } } protected override void UpdateEditorShape(UpdateEditorContext context, ContentPart part) { @@ -49,8 +51,10 @@ protected override void UpdateEditorShape(UpdateEditorContext context, ContentPa return; var templatePart = part.As(); - context.Updater.TryUpdateModel(templatePart, _prefix, null, null); - BuildEditorShape(context, part); + if (templatePart != null) { + context.Updater.TryUpdateModel(templatePart, _prefix, null, null); + BuildEditorShape(context, part); + } } } } diff --git a/src/Orchard/Data/MapAsRecordAttribute.cs b/src/Orchard/Data/MapAsRecordAttribute.cs new file mode 100644 index 00000000000..2ef6abecd41 --- /dev/null +++ b/src/Orchard/Data/MapAsRecordAttribute.cs @@ -0,0 +1,18 @@ +using System; + +namespace Orchard.Data { + /// + /// Marks whether a class should be mapped as an NHibernate record + /// + public class MapAsRecordAttribute : Attribute { + private readonly bool _enabled; + + public MapAsRecordAttribute() : this(true) { } + + public MapAsRecordAttribute(bool enabled) { + _enabled = enabled; + } + + public bool Enabled => _enabled; + } +} \ No newline at end of file diff --git a/src/Orchard/DisplayManagement/Descriptors/DefaultShapeTableManager.cs b/src/Orchard/DisplayManagement/Descriptors/DefaultShapeTableManager.cs index 758dcc37336..0c84c900d73 100644 --- a/src/Orchard/DisplayManagement/Descriptors/DefaultShapeTableManager.cs +++ b/src/Orchard/DisplayManagement/Descriptors/DefaultShapeTableManager.cs @@ -3,6 +3,7 @@ using System.Linq; using Autofac.Features.Metadata; using Orchard.Caching; +using Orchard.ContentManagement; using Orchard.Environment; using Orchard.Environment.Extensions; using Orchard.Environment.Extensions.Models; @@ -19,6 +20,16 @@ public class DefaultShapeTableManager : IShapeTableManager { private readonly IParallelCacheContext _parallelCacheContext; private readonly Work> _shapeTableEventHandlersWork; + /// + /// Group all ShapeAlterations by Feature, so we may more easily sort those by their + /// priorities and dependencies. The reason for this is that we may often end up with + /// orders of magnitude more ShapeAlterations than Features, so sorting directly the + /// former may end up being too expensive. + /// We can enable this through HostComponents.config as a safety measure in case this + /// breaks some frontend. + /// + public bool GroupByFeatures { get; set; } + public DefaultShapeTableManager( IEnumerable> bindingStrategies, IExtensionManager extensionManager, @@ -50,11 +61,36 @@ public ShapeTable GetShapeTable(string themeName) { return builder.BuildAlterations().ToReadOnlyCollection(); }); - var alterations = alterationSets - .SelectMany(shapeAlterations => shapeAlterations) - .Where(alteration => IsModuleOrRequestedTheme(alteration, themeName)) - .OrderByDependenciesAndPriorities(AlterationHasDependency, GetPriority) - .ToList(); + List alterations; + if (GroupByFeatures) { + var unsortedAlterations = alterationSets + .SelectMany(shapeAlterations => shapeAlterations) + .Where(alteration => IsModuleOrRequestedTheme(alteration, themeName)); + + // Group all ShapeAlterations by Feature, so we may more easily sort those by their + // priorities and dependencies. The reason for this is that we may often end up with + // orders of magnitude more ShapeAlterations than Features, so sorting directly the + // former may end up being too expensive. + var alterationsByFeature = unsortedAlterations + .GroupBy(sa => sa.Feature.Descriptor.Id) + .Select(g => new AlterationGroup { + Feature = g.First().Feature, + Alterations = g + }); + var orderedGroups = alterationsByFeature + .OrderByDependenciesAndPriorities(AlterationHasDependency, GetPriority); + alterations = orderedGroups + .SelectMany(g => g.Alterations) + .ToList(); + } + else { + alterations = alterationSets + .SelectMany(shapeAlterations => shapeAlterations) + .Where(alteration => IsModuleOrRequestedTheme(alteration, themeName)) + .OrderByDependenciesAndPriorities(AlterationHasDependency, GetPriority) + .ToList(); + } + var descriptors = alterations.GroupBy(alteration => alteration.ShapeType, StringComparer.OrdinalIgnoreCase) .Select(group => group.Aggregate( @@ -64,8 +100,8 @@ public ShapeTable GetShapeTable(string themeName) { return descriptor; })).ToList(); - foreach(var descriptor in descriptors) { - foreach(var alteration in alterations.Where(a => a.ShapeType == descriptor.ShapeType).ToList()) { + foreach (var descriptor in descriptors) { + foreach (var alteration in alterations.Where(a => a.ShapeType == descriptor.ShapeType).ToList()) { var local = new ShapeDescriptor { ShapeType = descriptor.ShapeType }; alteration.Alter(local); descriptor.BindingSources.Add(local.BindingSource); @@ -131,5 +167,18 @@ private bool IsBaseTheme(string featureName, string themeName) { } return false; } + + class AlterationGroup { + public Feature Feature { get; set; } + public IEnumerable Alterations { get; set; } + } + private static int GetPriority(AlterationGroup shapeAlteration) { + return shapeAlteration.Feature.Descriptor.Priority; + } + + private static bool AlterationHasDependency(AlterationGroup item, AlterationGroup subject) { + return ExtensionManager.HasDependency(item.Feature.Descriptor, subject.Feature.Descriptor); + } + } } diff --git a/src/Orchard/Environment/Extensions/ExtensionManager.cs b/src/Orchard/Environment/Extensions/ExtensionManager.cs index d1dab4feb7b..19420c45c0a 100644 --- a/src/Orchard/Environment/Extensions/ExtensionManager.cs +++ b/src/Orchard/Environment/Extensions/ExtensionManager.cs @@ -10,6 +10,13 @@ using Orchard.Utility; using Orchard.Utility.Extensions; using Orchard.Exceptions; +using System.Diagnostics; +using NHibernate.Cfg; +using NHibernate.Linq.Functions; +using System.Web.Http.Results; +using System.Threading; +using System.Security.Cryptography; +using System.Text; namespace Orchard.Environment.Extensions { public class ExtensionManager : IExtensionManager { @@ -18,10 +25,15 @@ public class ExtensionManager : IExtensionManager { private readonly ICacheManager _cacheManager; private readonly IParallelCacheContext _parallelCacheContext; private readonly IEnumerable _loaders; - + public Localizer T { get; set; } public ILogger Logger { get; set; } + /// + /// Allow disabling parallel behavior through HostComponents.config + /// + public bool ParallelizationDisabled { get; set; } + public ExtensionManager( IEnumerable folders, IEnumerable loaders, @@ -36,8 +48,11 @@ public ExtensionManager( _loaders = loaders.OrderBy(x => x.Order).ToArray(); T = NullLocalizer.Instance; Logger = NullLogger.Instance; + + _md5 = MD5.Create(); } + private MD5 _md5; // This method does not load extension types, simply parses extension manifests from // the filesystem. public ExtensionDescriptor GetExtension(string id) { @@ -91,10 +106,34 @@ internal static bool HasDependency(FeatureDescriptor item, FeatureDescriptor sub public IEnumerable LoadFeatures(IEnumerable featureDescriptors) { Logger.Information("Loading features"); - var result = - _parallelCacheContext - .RunInParallel(featureDescriptors, descriptor => _cacheManager.Get(descriptor.Id, true, ctx => LoadFeature(descriptor))) - .ToArray(); + // generate a cachekey by hashing the ids of all feature descriptors + string cacheKey; + lock (_md5) { + cacheKey = BitConverter.ToString( + _md5.ComputeHash( + Encoding.UTF8.GetBytes( + string.Join(";", + featureDescriptors + .Select(fd => fd.Id) + .OrderBy(x => x))))); + } + + var result = _cacheManager.Get(cacheKey, + true, + ctk => { + if (ParallelizationDisabled) { + return featureDescriptors.Select(descriptor => _cacheManager + .Get(descriptor.Id, true, ctx => LoadFeature(descriptor))) + .ToArray(); + } + else { + return _parallelCacheContext + .RunInParallel(featureDescriptors, + descriptor => _cacheManager + .Get(descriptor.Id, true, ctx => LoadFeature(descriptor))) + .ToArray(); + } + }); Logger.Information("Done loading features"); return result; diff --git a/src/Orchard/Environment/ShellBuilders/CompositionStrategy.cs b/src/Orchard/Environment/ShellBuilders/CompositionStrategy.cs index 332d7096491..5a4e48480d2 100644 --- a/src/Orchard/Environment/ShellBuilders/CompositionStrategy.cs +++ b/src/Orchard/Environment/ShellBuilders/CompositionStrategy.cs @@ -6,6 +6,7 @@ using Autofac.Core; using Orchard.ContentManagement; using Orchard.ContentManagement.Records; +using Orchard.Data; using Orchard.Environment.Configuration; using Orchard.Environment.Descriptor.Models; using Orchard.Environment.Extensions; @@ -96,7 +97,7 @@ private IEnumerable ExpandDependenciesInternal(IDictionary() + .FirstOrDefault(); + + return ((type.Namespace ?? "").EndsWith(".Models") || (type.Namespace ?? "").EndsWith(".Records") || mapAsRecordAttr?.Enabled == true) && + mapAsRecordAttr?.Enabled != false && type.GetProperty("Id") != null && (type.GetProperty("Id").GetAccessors()).All(x => x.IsVirtual) && !type.IsSealed && diff --git a/src/Orchard/FileSystems/Media/FileSystemStorageProvider.cs b/src/Orchard/FileSystems/Media/FileSystemStorageProvider.cs index 782590892a7..ab0abfd2652 100644 --- a/src/Orchard/FileSystems/Media/FileSystemStorageProvider.cs +++ b/src/Orchard/FileSystems/Media/FileSystemStorageProvider.cs @@ -34,10 +34,27 @@ public FileSystemStorageProvider(ShellSettings settings) { _publicPath = appPath + "Media/" + settings.Name + "/"; T = NullLocalizer.Instance; + MaxPathLength = 260; } public Localizer T { get; set; } + public int MaxPathLength { + get; set; + // The public setter allows injecting this from Sites.MyTenant.Config or Sites.config, by using + // an AutoFac component: + /* + + + + + + + */ + } + /// /// Maps a relative path into the storage path. /// @@ -335,6 +352,17 @@ public IStorageFile CreateFile(string path) { if (!Directory.Exists(dirName)) { Directory.CreateDirectory(dirName); } + //Path.GetFileNameWithoutExtension(fileInfo.Name) + // If absolute path is longer than the maximum path length (260 characters), file cannot be saved. + if (fileInfo.FullName.Length > MaxPathLength) { + var fileName = Path.GetFileNameWithoutExtension(fileInfo.Name); + var extension = fileInfo.Extension; + // try to generate a shorter path for the file + var nameHash = fileName.GetHashCode().ToString("x"); + // Hopefully this new path is short enough now + path = Combine(Path.GetDirectoryName(path), nameHash + extension); + fileInfo = new FileInfo(MapStorage(path)); + } File.WriteAllBytes(fileInfo.FullName, new byte[0]); return new FileSystemStorageFile(Fix(path), fileInfo); @@ -367,6 +395,7 @@ public bool TrySaveStream(string path, Stream inputStream) { /// The relative path to the file to be created. /// The stream to be saved. /// If the stream can't be saved due to access permissions. + /// If the path is invalid. public void SaveStream(string path, Stream inputStream) { // Create the file. // The CreateFile method will map the still relative path diff --git a/src/Orchard/Localization/Services/CurrentCultureWorkContext.cs b/src/Orchard/Localization/Services/CurrentCultureWorkContext.cs index 16208ccbf6e..7efe5c68ec7 100644 --- a/src/Orchard/Localization/Services/CurrentCultureWorkContext.cs +++ b/src/Orchard/Localization/Services/CurrentCultureWorkContext.cs @@ -7,11 +7,14 @@ namespace Orchard.Localization.Services { public class CurrentCultureWorkContext : IWorkContextStateProvider { private readonly IEnumerable _cultureSelectors; private readonly IHttpContextAccessor _httpContextAccessor; + private readonly ICultureManager _cultureManager; public CurrentCultureWorkContext(IEnumerable cultureSelectors, - IHttpContextAccessor httpContextAccessor) { + IHttpContextAccessor httpContextAccessor, + ICultureManager cultureManager) { _cultureSelectors = cultureSelectors; _httpContextAccessor = httpContextAccessor; + _cultureManager = cultureManager; } public Func Get(string name) { @@ -25,11 +28,13 @@ public Func Get(string name) { private string GetCurrentCulture() { var httpContext = _httpContextAccessor.Current(); + var supportedCultures = _cultureManager.ListCultures().ToList(); + var culture = _cultureSelectors .Select(c => c.GetCulture(httpContext)) .Where(c => c != null) .OrderByDescending(c => c.Priority) - .FirstOrDefault(c => !String.IsNullOrEmpty(c.CultureName)); + .FirstOrDefault(c => !String.IsNullOrEmpty(c.CultureName) && supportedCultures.Any(s => s.Equals(c.CultureName, StringComparison.OrdinalIgnoreCase))); return culture == null ? String.Empty : culture.CultureName; } diff --git a/src/Orchard/Localization/Services/DefaultCultureManager.cs b/src/Orchard/Localization/Services/DefaultCultureManager.cs index 49344b98750..16c6ade475d 100644 --- a/src/Orchard/Localization/Services/DefaultCultureManager.cs +++ b/src/Orchard/Localization/Services/DefaultCultureManager.cs @@ -62,12 +62,36 @@ public string GetCurrentCulture(HttpContextBase requestContext) { return _workContextAccessor.GetContext().CurrentCulture; } + protected Dictionary GetAllCulturesById() { + return _cacheManager.Get("all_culture_records_by_id", true, context => { + context.Monitor(_signals.When("culturesChanged")); + + return _cultureRepository.Table + .ToDictionary(cr => cr.Id); + }); + } public CultureRecord GetCultureById(int id) { - return _cultureRepository.Get(id); + var cultures = GetAllCulturesById(); + CultureRecord result; + cultures.TryGetValue(id, out result); + + return result; } + protected Dictionary GetAllCulturesByName() { + return _cacheManager.Get("all_culture_records_by_name", true, context => { + context.Monitor(_signals.When("culturesChanged")); + + return _cultureRepository.Table + .ToDictionary(cr => cr.Culture); + }); + } public CultureRecord GetCultureByName(string cultureName) { - return _cultureRepository.Get(cr => cr.Culture == cultureName); + var cultures = GetAllCulturesByName(); + CultureRecord result; + cultures.TryGetValue(cultureName, out result); + + return result; } public string GetSiteCulture() { diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index 97d11be70f2..d2698b5dba3 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -113,9 +113,7 @@ 3.5 - - True - + ..\packages\Microsoft.AspNet.WebApi.Client.5.2.7\lib\net45\System.Net.Http.Formatting.dll @@ -159,6 +157,7 @@ + diff --git a/src/Orchard/Validation/PathValidation.cs b/src/Orchard/Validation/PathValidation.cs index 3d0b5b864c3..85370a87a81 100644 --- a/src/Orchard/Validation/PathValidation.cs +++ b/src/Orchard/Validation/PathValidation.cs @@ -15,7 +15,7 @@ public static class PathValidation { /// The base path which boundaries are not to be transposed. /// The path to determine. /// The mapped path if valid. - /// If the path is invalid. + /// If the path is invalid. public static string ValidatePath(string basePath, string mappedPath) { bool valid = false;