From c9e14f9b82c05f96bb6cef494099103aacf7758b Mon Sep 17 00:00:00 2001 From: "matteo.piovanelli" Date: Mon, 17 Oct 2016 12:54:53 +0200 Subject: [PATCH 01/16] Modified the OutputCache Module based on the enhancement proposed in Issue 5811, by adding a VaryByRequestCookies property to the CacheSettingsPart to enable the generation of the Cache Key based on cookies --- .../Orchard.OutputCache/Controllers/AdminController.cs | 2 ++ .../Orchard.OutputCache/Filters/OutputCacheFilter.cs | 6 ++++++ .../Modules/Orchard.OutputCache/Models/CacheSettings.cs | 2 ++ .../Orchard.OutputCache/Models/CacheSettingsPart.cs | 5 +++++ .../Orchard.OutputCache/ViewModels/IndexViewModel.cs | 1 + .../Modules/Orchard.OutputCache/Views/Admin/Index.cshtml | 8 +++++++- 6 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/Controllers/AdminController.cs index f8a0427068c..a2798425da4 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Controllers/AdminController.cs @@ -89,6 +89,7 @@ public ActionResult Index() { DefaultMaxAge = settings.DefaultMaxAge, VaryByQueryStringParameters = settings.VaryByQueryStringParameters, VaryByRequestHeaders = settings.VaryByRequestHeaders, + VaryByRequestCookies = settings.VaryByRequestCookies, IgnoredUrls = settings.IgnoredUrls, IgnoreNoCache = settings.IgnoreNoCache, VaryByCulture = settings.VaryByCulture, @@ -116,6 +117,7 @@ public ActionResult IndexPost() { settings.DefaultMaxAge = model.DefaultMaxAge; settings.VaryByQueryStringParameters = model.VaryByQueryStringParameters; settings.VaryByRequestHeaders = model.VaryByRequestHeaders; + settings.VaryByRequestCookies = model.VaryByRequestCookies; settings.IgnoredUrls = model.IgnoredUrls; settings.IgnoreNoCache = model.IgnoreNoCache; settings.VaryByCulture = model.VaryByCulture; diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs index 548012e6bac..4e0bc04a31e 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs @@ -397,6 +397,12 @@ protected virtual IDictionary GetCacheKeyParameters(ActionExecut result["HEADER:" + varyByRequestHeader] = requestHeaders[varyByRequestHeader]; } + // Vary by configured cookies. + var requestCookies = filterContext.RequestContext.HttpContext.Request.Cookies; + foreach (var varyByRequestCookies in CacheSettings.VaryByRequestCookies) { + if (requestCookies[varyByRequestCookies] != null) + result["COOKIE:" + varyByRequestCookies] = requestCookies[varyByRequestCookies].Value; + } // Vary by request culture if configured. if (CacheSettings.VaryByCulture) { diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Models/CacheSettings.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/Models/CacheSettings.cs index 62075c24d1c..7797d738201 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Models/CacheSettings.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Models/CacheSettings.cs @@ -14,6 +14,7 @@ public CacheSettings(CacheSettingsPart part) { VaryByQueryStringParameters = String.IsNullOrWhiteSpace(part.VaryByQueryStringParameters) ? null : part.VaryByQueryStringParameters.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToArray(); VaryByRequestHeaders = String.IsNullOrWhiteSpace(part.VaryByRequestHeaders) ? new HashSet() : new HashSet(part.VaryByRequestHeaders.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToArray()); VaryByRequestHeaders.Add("HOST"); // Always vary by host name/tenant. + VaryByRequestCookies = String.IsNullOrWhiteSpace(part.VaryByRequestCookies) ? new HashSet() : new HashSet(part.VaryByRequestCookies.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToArray()); IgnoredUrls = String.IsNullOrWhiteSpace(part.IgnoredUrls) ? null : part.IgnoredUrls.Split(new[] { "\n" }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToArray(); IgnoreNoCache = part.IgnoreNoCache; VaryByCulture = part.VaryByCulture; @@ -27,6 +28,7 @@ public CacheSettings(CacheSettingsPart part) { public int DefaultMaxAge { get; private set; } public IEnumerable VaryByQueryStringParameters { get; private set; } public ISet VaryByRequestHeaders { get; private set; } + public ISet VaryByRequestCookies { get; private set; } public IEnumerable IgnoredUrls { get; private set; } public bool IgnoreNoCache { get; private set; } public bool VaryByCulture { get; private set; } diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Models/CacheSettingsPart.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/Models/CacheSettingsPart.cs index b11eb3fae76..69e8441fd07 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Models/CacheSettingsPart.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Models/CacheSettingsPart.cs @@ -44,6 +44,11 @@ public string VaryByRequestHeaders { } } + public string VaryByRequestCookies { + get { return this.Retrieve(x => x.VaryByRequestCookies); } + set { this.Store(x => x.VaryByRequestCookies, value); } + } + public string IgnoredUrls { get { return this.Retrieve(x => x.IgnoredUrls); } set { this.Store(x => x.IgnoredUrls, value); } diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/ViewModels/IndexViewModel.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/ViewModels/IndexViewModel.cs index 1cda10adad6..b79ff5509ba 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/ViewModels/IndexViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/ViewModels/IndexViewModel.cs @@ -11,6 +11,7 @@ public class IndexViewModel { [Range(0, Int32.MaxValue), Required] public int DefaultMaxAge { get; set; } public string VaryByQueryStringParameters { get; set; } public string VaryByRequestHeaders { get; set; } + public string VaryByRequestCookies { get; set; } public string IgnoredUrls { get; set; } public bool IgnoreNoCache { get; set; } public bool VaryByCulture { get; set; } diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Views/Admin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.OutputCache/Views/Admin/Index.cshtml index 960b43bb444..9750acb7e7b 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Views/Admin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Views/Admin/Index.cshtml @@ -43,7 +43,13 @@ @Html.TextBoxFor(m => m.VaryByRequestHeaders, new { @class = "text medium" }) @T("When defined, using comma separated values, sets caching to vary by the specified request headers.") - + +
+ + @Html.TextBoxFor(m => m.VaryByRequestCookies, new { @class = "text medium" }) + @T("When defined, using comma separated values, sets caching to vary via specified cookie string parameters") +
+
@Html.TextAreaFor(m => m.IgnoredUrls, new { @class = "text medium" }) From 58e59e2fca8d9d672d45dee661e11b9a7616dc19 Mon Sep 17 00:00:00 2001 From: HermesSbicego-Laser Date: Wed, 19 Oct 2016 16:30:12 +0200 Subject: [PATCH 02/16] - added EventHandler in order to partecipate in cachekey generation --- .../Filters/OutputCacheFilter.cs | 13 ++++++++++++- .../Orchard.OutputCache/ICachingEventHandler.cs | 12 ++++++++++++ .../Orchard.OutputCache/Orchard.OutputCache.csproj | 1 + 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/Orchard.Web/Modules/Orchard.OutputCache/ICachingEventHandler.cs diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs index 548012e6bac..8df84b69f18 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs @@ -41,6 +41,7 @@ public class OutputCacheFilter : FilterProvider, IActionFilter, IResultFilter, I private readonly ICacheService _cacheService; private readonly ISignals _signals; private readonly ShellSettings _shellSettings; + private readonly ICachingEventHandler _chachingEvents; private bool _isDisposed = false; public ILogger Logger { get; set; } @@ -55,7 +56,8 @@ public OutputCacheFilter( IClock clock, ICacheService cacheService, ISignals signals, - ShellSettings shellSettings) { + ShellSettings shellSettings, + ICachingEventHandler chachingEvents) { _cacheManager = cacheManager; _cacheStorageProvider = cacheStorageProvider; @@ -67,6 +69,7 @@ public OutputCacheFilter( _cacheService = cacheService; _signals = signals; _shellSettings = shellSettings; + _chachingEvents = chachingEvents; Logger = NullLogger.Instance; } @@ -610,6 +613,14 @@ protected virtual string ComputeCacheKey(string tenant, string absoluteUrl, IEnu } } + //make CacheKey morphable by external modules + try { + keyBuilder = _chachingEvents.ParticipateInCacheKey(keyBuilder); + } catch (UnauthorizedAccessException ex) { + throw new UnauthorizedAccessException(); + } catch { } + + return keyBuilder.ToString(); } diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/ICachingEventHandler.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/ICachingEventHandler.cs new file mode 100644 index 00000000000..6e9aebf5a7b --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/ICachingEventHandler.cs @@ -0,0 +1,12 @@ +using Orchard.Events; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web; + +namespace Orchard.OutputCache { + public interface ICachingEventHandler : IEventHandler { + StringBuilder ParticipateInCacheKey(StringBuilder key); + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Orchard.OutputCache.csproj b/src/Orchard.Web/Modules/Orchard.OutputCache/Orchard.OutputCache.csproj index a3a7fa74c7f..9a4520288d4 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Orchard.OutputCache.csproj +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Orchard.OutputCache.csproj @@ -103,6 +103,7 @@ + From 350cbbd183414a41cf0886967c918d9482e47fea Mon Sep 17 00:00:00 2001 From: HermesSbicego-Laser Date: Wed, 19 Oct 2016 17:40:58 +0200 Subject: [PATCH 03/16] - typo chaching > caching --- .../Orchard.OutputCache/Filters/OutputCacheFilter.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs index 8df84b69f18..b8ddff8398e 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs @@ -41,7 +41,7 @@ public class OutputCacheFilter : FilterProvider, IActionFilter, IResultFilter, I private readonly ICacheService _cacheService; private readonly ISignals _signals; private readonly ShellSettings _shellSettings; - private readonly ICachingEventHandler _chachingEvents; + private readonly ICachingEventHandler _cachingEvents; private bool _isDisposed = false; public ILogger Logger { get; set; } @@ -57,7 +57,7 @@ public OutputCacheFilter( ICacheService cacheService, ISignals signals, ShellSettings shellSettings, - ICachingEventHandler chachingEvents) { + ICachingEventHandler cachingEvents) { _cacheManager = cacheManager; _cacheStorageProvider = cacheStorageProvider; @@ -69,7 +69,7 @@ public OutputCacheFilter( _cacheService = cacheService; _signals = signals; _shellSettings = shellSettings; - _chachingEvents = chachingEvents; + _cachingEvents = cachingEvents; Logger = NullLogger.Instance; } @@ -615,7 +615,7 @@ protected virtual string ComputeCacheKey(string tenant, string absoluteUrl, IEnu //make CacheKey morphable by external modules try { - keyBuilder = _chachingEvents.ParticipateInCacheKey(keyBuilder); + keyBuilder = _cachingEvents.ParticipateInCacheKey(keyBuilder); } catch (UnauthorizedAccessException ex) { throw new UnauthorizedAccessException(); } catch { } From 1dcee8aae85741975c6589664acbfd80f92514f8 Mon Sep 17 00:00:00 2001 From: HermesSbicego-Laser Date: Wed, 19 Oct 2016 16:30:12 +0200 Subject: [PATCH 04/16] - typo chaching > caching - added EventHandler in order to partecipate in cachekey generation --- .../Filters/OutputCacheFilter.cs | 13 ++++++++++++- .../Orchard.OutputCache/ICachingEventHandler.cs | 12 ++++++++++++ .../Orchard.OutputCache/Orchard.OutputCache.csproj | 1 + 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/Orchard.Web/Modules/Orchard.OutputCache/ICachingEventHandler.cs diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs index 548012e6bac..b8ddff8398e 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs @@ -41,6 +41,7 @@ public class OutputCacheFilter : FilterProvider, IActionFilter, IResultFilter, I private readonly ICacheService _cacheService; private readonly ISignals _signals; private readonly ShellSettings _shellSettings; + private readonly ICachingEventHandler _cachingEvents; private bool _isDisposed = false; public ILogger Logger { get; set; } @@ -55,7 +56,8 @@ public OutputCacheFilter( IClock clock, ICacheService cacheService, ISignals signals, - ShellSettings shellSettings) { + ShellSettings shellSettings, + ICachingEventHandler cachingEvents) { _cacheManager = cacheManager; _cacheStorageProvider = cacheStorageProvider; @@ -67,6 +69,7 @@ public OutputCacheFilter( _cacheService = cacheService; _signals = signals; _shellSettings = shellSettings; + _cachingEvents = cachingEvents; Logger = NullLogger.Instance; } @@ -610,6 +613,14 @@ protected virtual string ComputeCacheKey(string tenant, string absoluteUrl, IEnu } } + //make CacheKey morphable by external modules + try { + keyBuilder = _cachingEvents.ParticipateInCacheKey(keyBuilder); + } catch (UnauthorizedAccessException ex) { + throw new UnauthorizedAccessException(); + } catch { } + + return keyBuilder.ToString(); } diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/ICachingEventHandler.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/ICachingEventHandler.cs new file mode 100644 index 00000000000..6e9aebf5a7b --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/ICachingEventHandler.cs @@ -0,0 +1,12 @@ +using Orchard.Events; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web; + +namespace Orchard.OutputCache { + public interface ICachingEventHandler : IEventHandler { + StringBuilder ParticipateInCacheKey(StringBuilder key); + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Orchard.OutputCache.csproj b/src/Orchard.Web/Modules/Orchard.OutputCache/Orchard.OutputCache.csproj index a3a7fa74c7f..9a4520288d4 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Orchard.OutputCache.csproj +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Orchard.OutputCache.csproj @@ -103,6 +103,7 @@ + From 548b5d7d8fd95982cc04adc42272152ec327d1c0 Mon Sep 17 00:00:00 2001 From: HermesSbicego-Laser Date: Fri, 21 Oct 2016 09:37:07 +0200 Subject: [PATCH 05/16] - Method renamed - try catch removed --- .../Orchard.OutputCache/Filters/OutputCacheFilter.cs | 7 +------ .../Modules/Orchard.OutputCache/ICachingEventHandler.cs | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs index b8ddff8398e..e87eeedc2fb 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs @@ -614,12 +614,7 @@ protected virtual string ComputeCacheKey(string tenant, string absoluteUrl, IEnu } //make CacheKey morphable by external modules - try { - keyBuilder = _cachingEvents.ParticipateInCacheKey(keyBuilder); - } catch (UnauthorizedAccessException ex) { - throw new UnauthorizedAccessException(); - } catch { } - + _cachingEvents.KeyGenerated(keyBuilder); return keyBuilder.ToString(); } diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/ICachingEventHandler.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/ICachingEventHandler.cs index 6e9aebf5a7b..a2dbc640e29 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/ICachingEventHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/ICachingEventHandler.cs @@ -7,6 +7,6 @@ namespace Orchard.OutputCache { public interface ICachingEventHandler : IEventHandler { - StringBuilder ParticipateInCacheKey(StringBuilder key); + void KeyGenerated(StringBuilder key); } } \ No newline at end of file From 2bb81eef31b092c8f78b19d9e8f21300d32cf3ba Mon Sep 17 00:00:00 2001 From: HermesSbicego-Laser Date: Fri, 21 Oct 2016 11:46:08 +0200 Subject: [PATCH 06/16] - Added attachments logic --- .../Orchard.Email/Models/EmailMessage.cs | 8 +++++++- .../Services/SmtpMessageChannel.cs | 20 ++++++++++++------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Email/Models/EmailMessage.cs b/src/Orchard.Web/Modules/Orchard.Email/Models/EmailMessage.cs index 3edcd8731aa..8c588ce91c3 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Models/EmailMessage.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Models/EmailMessage.cs @@ -1,4 +1,6 @@ -namespace Orchard.Email.Models { +using System.Collections.Generic; + +namespace Orchard.Email.Models { public class EmailMessage { public string Subject { get; set; } public string Body { get; set; } @@ -7,5 +9,9 @@ public class EmailMessage { public string From { get; set; } public string Bcc { get; set; } public string Cc { get; set; } + /// + /// IEnumerable of strings representing attachments paths + /// + public IEnumerable Attachments { get; set; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs b/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs index 0ab833e6bbc..1d869813aa0 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs @@ -9,6 +9,8 @@ using Orchard.DisplayManagement; using Orchard.Logging; using Orchard.Email.Models; +using System.Linq; +using System.IO; namespace Orchard.Email.Services { public class SmtpMessageChannel : Component, ISmtpChannel, IDisposable { @@ -51,7 +53,8 @@ public void Process(IDictionary parameters) { ReplyTo = Read(parameters, "ReplyTo"), From = Read(parameters, "From"), Bcc = Read(parameters, "Bcc"), - Cc = Read(parameters, "CC") + Cc = Read(parameters, "CC"), + Attachments = (IEnumerable)parameters["Attachments"] }; if (emailMessage.Recipients.Length == 0) { @@ -105,8 +108,7 @@ public void Process(IDictionary parameters) { if (!String.IsNullOrWhiteSpace(emailMessage.From)) { mailMessage.From = new MailAddress(emailMessage.From); - } - else { + } else { // Take 'From' address from site settings or web.config. mailMessage.From = !String.IsNullOrWhiteSpace(_smtpSettings.Address) ? new MailAddress(_smtpSettings.Address) @@ -119,9 +121,13 @@ public void Process(IDictionary parameters) { } } + foreach (var attachmentPath in emailMessage.Attachments) { + if (File.Exists(attachmentPath)) { + mailMessage.Attachments.Add(new Attachment(attachmentPath)); + } + } _smtpClientField.Value.Send(mailMessage); - } - catch (Exception e) { + } catch (Exception e) { Logger.Error(e, "Could not send email"); } } @@ -129,7 +135,7 @@ public void Process(IDictionary parameters) { private SmtpClient CreateSmtpClient() { // If no properties are set in the dashboard, use the web.config value. if (String.IsNullOrWhiteSpace(_smtpSettings.Host)) { - return new SmtpClient(); + return new SmtpClient(); } var smtpClient = new SmtpClient { @@ -155,7 +161,7 @@ private string Read(IDictionary dictionary, string key) { } private IEnumerable ParseRecipients(string recipients) { - return recipients.Split(new[] {',', ';'}, StringSplitOptions.RemoveEmptyEntries); + return recipients.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); } } } \ No newline at end of file From a4c816b29180dde88964e9d55207efd73de4d561 Mon Sep 17 00:00:00 2001 From: HermesSbicego-Laser Date: Fri, 21 Oct 2016 11:55:38 +0200 Subject: [PATCH 07/16] - missing Attachments Key fix --- .../Modules/Orchard.Email/Services/SmtpMessageChannel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs b/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs index 1d869813aa0..ff44a551d8e 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs @@ -54,7 +54,7 @@ public void Process(IDictionary parameters) { From = Read(parameters, "From"), Bcc = Read(parameters, "Bcc"), Cc = Read(parameters, "CC"), - Attachments = (IEnumerable)parameters["Attachments"] + Attachments = (IEnumerable)(parameters.ContainsKey("Attachments") ? parameters["Attachments"] : new List()) }; if (emailMessage.Recipients.Length == 0) { From 580b79c24db2da9b7d97039b4fd6db03412fb5c6 Mon Sep 17 00:00:00 2001 From: HermesSbicego-Laser Date: Fri, 21 Oct 2016 11:46:08 +0200 Subject: [PATCH 08/16] - Added attachments logic --- .../Orchard.Email/Models/EmailMessage.cs | 8 ++++++- .../Services/SmtpMessageChannel.cs | 22 +++++++++++++------ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Email/Models/EmailMessage.cs b/src/Orchard.Web/Modules/Orchard.Email/Models/EmailMessage.cs index 3edcd8731aa..8c588ce91c3 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Models/EmailMessage.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Models/EmailMessage.cs @@ -1,4 +1,6 @@ -namespace Orchard.Email.Models { +using System.Collections.Generic; + +namespace Orchard.Email.Models { public class EmailMessage { public string Subject { get; set; } public string Body { get; set; } @@ -7,5 +9,9 @@ public class EmailMessage { public string From { get; set; } public string Bcc { get; set; } public string Cc { get; set; } + /// + /// IEnumerable of strings representing attachments paths + /// + public IEnumerable Attachments { get; set; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs b/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs index 0ab833e6bbc..02e26892a37 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs @@ -9,6 +9,8 @@ using Orchard.DisplayManagement; using Orchard.Logging; using Orchard.Email.Models; +using System.Linq; +using System.IO; namespace Orchard.Email.Services { public class SmtpMessageChannel : Component, ISmtpChannel, IDisposable { @@ -51,7 +53,8 @@ public void Process(IDictionary parameters) { ReplyTo = Read(parameters, "ReplyTo"), From = Read(parameters, "From"), Bcc = Read(parameters, "Bcc"), - Cc = Read(parameters, "CC") + Cc = Read(parameters, "CC"), + Attachments = (IEnumerable)(parameters.ContainsKey("Attachments") ? parameters["Attachments"] : new List()) }; if (emailMessage.Recipients.Length == 0) { @@ -105,8 +108,7 @@ public void Process(IDictionary parameters) { if (!String.IsNullOrWhiteSpace(emailMessage.From)) { mailMessage.From = new MailAddress(emailMessage.From); - } - else { + } else { // Take 'From' address from site settings or web.config. mailMessage.From = !String.IsNullOrWhiteSpace(_smtpSettings.Address) ? new MailAddress(_smtpSettings.Address) @@ -119,9 +121,15 @@ public void Process(IDictionary parameters) { } } + foreach (var attachmentPath in emailMessage.Attachments) { + if (File.Exists(attachmentPath)) { + mailMessage.Attachments.Add(new Attachment(attachmentPath)); + } else { + throw new FileNotFoundException(T("One or more attachments not found.").Text); + } + } _smtpClientField.Value.Send(mailMessage); - } - catch (Exception e) { + } catch (Exception e) { Logger.Error(e, "Could not send email"); } } @@ -129,7 +137,7 @@ public void Process(IDictionary parameters) { private SmtpClient CreateSmtpClient() { // If no properties are set in the dashboard, use the web.config value. if (String.IsNullOrWhiteSpace(_smtpSettings.Host)) { - return new SmtpClient(); + return new SmtpClient(); } var smtpClient = new SmtpClient { @@ -155,7 +163,7 @@ private string Read(IDictionary dictionary, string key) { } private IEnumerable ParseRecipients(string recipients) { - return recipients.Split(new[] {',', ';'}, StringSplitOptions.RemoveEmptyEntries); + return recipients.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); } } } \ No newline at end of file From e50bd607b7f8e4047bf2a2c58fd31cf626aa198e Mon Sep 17 00:00:00 2001 From: HermesSbicego-Laser Date: Tue, 25 Oct 2016 09:18:24 +0200 Subject: [PATCH 09/16] - Formatted Code (Rebracer) --- .../Modules/Orchard.Email/Services/SmtpMessageChannel.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs b/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs index 02e26892a37..bb2dc3c6f30 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs @@ -108,7 +108,8 @@ public void Process(IDictionary parameters) { if (!String.IsNullOrWhiteSpace(emailMessage.From)) { mailMessage.From = new MailAddress(emailMessage.From); - } else { + } + else { // Take 'From' address from site settings or web.config. mailMessage.From = !String.IsNullOrWhiteSpace(_smtpSettings.Address) ? new MailAddress(_smtpSettings.Address) @@ -124,12 +125,14 @@ public void Process(IDictionary parameters) { foreach (var attachmentPath in emailMessage.Attachments) { if (File.Exists(attachmentPath)) { mailMessage.Attachments.Add(new Attachment(attachmentPath)); - } else { + } + else { throw new FileNotFoundException(T("One or more attachments not found.").Text); } } _smtpClientField.Value.Send(mailMessage); - } catch (Exception e) { + } + catch (Exception e) { Logger.Error(e, "Could not send email"); } } From ce8a61ed86f66a50c67adce24c6d84440cc61787 Mon Sep 17 00:00:00 2001 From: "matteo.piovanelli" Date: Wed, 26 Oct 2016 11:46:24 +0200 Subject: [PATCH 10/16] Fixes #7346 --- .../Views/WidgetFiltersControl.cshtml | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Widgets/Views/WidgetFiltersControl.cshtml b/src/Orchard.Web/Modules/Orchard.Widgets/Views/WidgetFiltersControl.cshtml index 5d6fdac181b..3e54450a269 100644 --- a/src/Orchard.Web/Modules/Orchard.Widgets/Views/WidgetFiltersControl.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Widgets/Views/WidgetFiltersControl.cshtml @@ -9,8 +9,8 @@ var returnUrl = Request.RawUrl; }
- @if (layers.Any()) { - using (Html.BeginForm("index", "admin", FormMethod.Get, new { area = "Orchard.Widgets" })) { + @using (Html.BeginForm("index", "admin", FormMethod.Get, new { area = "Orchard.Widgets" })) { + if (layers.Any()) {
- @Html.SelectOption((string)Model.CurrentCulture, "", T("any (show all)").ToString()) - @foreach (var culture in cultures) { - @Html.SelectOption((string)Model.CurrentCulture, (string)culture, System.Globalization.CultureInfo.GetCultureInfo(culture).DisplayName) - } - - -
+
+ @Html.Link(T("Add a new layer...").Text, Url.Action("AddLayer", "Admin", new { area = "Orchard.Widgets", returnUrl })) +
+ if (cultures.Count() > 1) { +
+ + + +
} } From 1b511b2692d1890b658b13f9dfd32f5caca3da09 Mon Sep 17 00:00:00 2001 From: HermesSbicego-Laser Date: Wed, 26 Oct 2016 18:50:35 +0200 Subject: [PATCH 11/16] - Implement what described in #6688 Supported Syntaxes for Request and Form tokens are: 1. QueryString:(param1) or Form:(param1) 2. QueryString:param1 or Form:param1 3. QueryString:(param1).SomeOtherTextToken or Form:(param1).SomeOtherTextToken If you want to Chain TextTokens you have to use the 3rd syntax the element (here param1) has been surrounded with brackets in order to preserve backward compatibility. --- .../Orchard.Tokens/Providers/RequestTokens.cs | 77 +++++++++++++++++-- 1 file changed, 70 insertions(+), 7 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RequestTokens.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RequestTokens.cs index a8380cd3a83..5e30bd90f23 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RequestTokens.cs +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RequestTokens.cs @@ -1,16 +1,21 @@ using System; +using System.Linq; using System.Web; using Orchard.ContentManagement; using Orchard.Localization; +using System.Globalization; +using System.Text.RegularExpressions; namespace Orchard.Tokens.Providers { public class RequestTokens : ITokenProvider { private readonly IWorkContextAccessor _workContextAccessor; private readonly IContentManager _contentManager; + private static string[] _textChainableTokens; public RequestTokens(IWorkContextAccessor workContextAccessor, IContentManager contentManager) { _workContextAccessor = workContextAccessor; _contentManager = contentManager; + _textChainableTokens = new string[] { "QueryString", "Form" }; T = NullLocalizer.Instance; } @@ -18,8 +23,8 @@ public RequestTokens(IWorkContextAccessor workContextAccessor, IContentManager c public void Describe(DescribeContext context) { context.For("Request", T("Http Request"), T("Current Http Request tokens.")) - .Token("QueryString:*", T("QueryString:"), T("The Query String value for the specified element.")) - .Token("Form:*", T("Form:"), T("The Form value for the specified element.")) + .Token("QueryString:*", T("QueryString:"), T("The Query String value for the specified element. If you want ot chain text, surround the with brackets [e.g. QueryString:(param1)].")) + .Token("Form:*", T("Form:"), T("The Form value for the specified element. If you want ot chain text, surround the with brackets [e.g. Form:(param1)].")) .Token("Route:*", T("Route:"), T("The Route value for the specified key.")) .Token("Content", T("Content"), T("The request routed Content Item."), "Content") ; @@ -29,20 +34,30 @@ public void Evaluate(EvaluateContext context) { if (_workContextAccessor.GetContext().HttpContext == null) { return; } - + /* Supported Syntaxes for Request and Form tokens are: + * 1. QueryString:(param1) or Form:(param1) + * 2. QueryString:param1 or Form:param1 + * 3. QueryString:(param1).SomeOtherTextToken or Form:(param1).SomeOtherTextToken + * + * If you want to Chain TextTokens you have to use 3rd syntax + * the element (here param1) has been surrounded with brackets in order to preserve backward compatibility. + */ context.For("Request", _workContextAccessor.GetContext().HttpContext.Request) .Token( - token => token.StartsWith("QueryString:", StringComparison.OrdinalIgnoreCase) ? token.Substring("QueryString:".Length) : null, - (token, request) => request.QueryString.Get(token) + FilterTokenParam, + (token, request) => { + return request.QueryString.Get(token); + } ) .Token( - token => token.StartsWith("Form:", StringComparison.OrdinalIgnoreCase) ? token.Substring("Form:".Length) : null, + FilterTokenParam, (token, request) => request.Form.Get(token) ) .Token( token => token.StartsWith("Route:", StringComparison.OrdinalIgnoreCase) ? token.Substring("Route:".Length) : null, (token, request) => GetRouteValue(token, request) ) + .Chain(FilterChainParam, "Text", (token, request) => request.QueryString.Get(token)) .Token("Content", (request) => DisplayText(GetRoutedContentItem(request)) ) @@ -98,5 +113,53 @@ private string DisplayText(IContent content) { return _contentManager.GetItemMetadata(content).DisplayText; } + + private static string FilterTokenParam(string token) { + string tokenPrefix; + int chainIndex, tokenLength; + if (token.IndexOf(":") == -1) { + return null; + } + tokenPrefix = token.Substring(0, token.IndexOf(":")); + if (!_textChainableTokens.Contains(tokenPrefix, StringComparer.OrdinalIgnoreCase)) { + return null; + } + + // use ")." as chars combination to discover the end of the parameter + chainIndex = token.IndexOf(").") + 1; + tokenLength = (tokenPrefix + ":").Length; + if (chainIndex == 0) {// ")." has not be found + return Regex.Replace(token.Substring(tokenLength), @"[\(|\)]", ""); + } + if (!token.StartsWith((tokenPrefix + ":"), StringComparison.OrdinalIgnoreCase) || chainIndex <= tokenLength) { + return null; + } + return Regex.Replace(token.Substring(tokenLength, chainIndex - tokenLength), @"[\(|\)]", ""); + } + private static Tuple FilterChainParam(string token) { + string tokenPrefix; + int chainIndex, tokenLength; + + if (token.IndexOf(":") == -1) { + return null; + } + tokenPrefix = token.Substring(0, token.IndexOf(":")); + if (!_textChainableTokens.Contains(tokenPrefix, StringComparer.OrdinalIgnoreCase)) { + return null; + } + + // use ")." as chars combination to discover the end of the parameter + chainIndex = token.IndexOf(").") + 1; + tokenLength = (tokenPrefix + ":").Length; + if (chainIndex == 0) { // ")." has not be found + return new Tuple(Regex.Replace(token.Substring(tokenLength), @"[\(|\)]", ""), token.Length.ToString()); + } + if (!token.StartsWith((tokenPrefix + ":"), StringComparison.OrdinalIgnoreCase) || chainIndex <= tokenLength) { + return null; + } + return new Tuple(Regex.Replace(token.Substring(tokenLength, chainIndex - tokenLength), @"[\(|\)]", ""), token.Substring(chainIndex + 1)); + + } } -} \ No newline at end of file + +} From 17ebdd2bfc53c7028aa71d36443b11942ac2a320 Mon Sep 17 00:00:00 2001 From: HermesSbicego-Laser Date: Wed, 26 Oct 2016 18:57:48 +0200 Subject: [PATCH 12/16] - typo --- .../Modules/Orchard.Tokens/Providers/RequestTokens.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RequestTokens.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RequestTokens.cs index 5e30bd90f23..ee5c9732450 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RequestTokens.cs +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RequestTokens.cs @@ -23,8 +23,8 @@ public RequestTokens(IWorkContextAccessor workContextAccessor, IContentManager c public void Describe(DescribeContext context) { context.For("Request", T("Http Request"), T("Current Http Request tokens.")) - .Token("QueryString:*", T("QueryString:"), T("The Query String value for the specified element. If you want ot chain text, surround the with brackets [e.g. QueryString:(param1)].")) - .Token("Form:*", T("Form:"), T("The Form value for the specified element. If you want ot chain text, surround the with brackets [e.g. Form:(param1)].")) + .Token("QueryString:*", T("QueryString:"), T("The Query String value for the specified element. If you want to chain text, surround the with brackets [e.g. QueryString:(param1)].")) + .Token("Form:*", T("Form:"), T("The Form value for the specified element. If you want to chain text, surround the with brackets [e.g. Form:(param1)].")) .Token("Route:*", T("Route:"), T("The Route value for the specified key.")) .Token("Content", T("Content"), T("The request routed Content Item."), "Content") ; From 7b09747fc9eaea71f653365e81d00cf2d82e964d Mon Sep 17 00:00:00 2001 From: HermesSbicego-Laser Date: Thu, 27 Oct 2016 09:05:17 +0200 Subject: [PATCH 13/16] inserted a better explanation on how to use the chains --- .../Modules/Orchard.Tokens/Providers/RequestTokens.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RequestTokens.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RequestTokens.cs index ee5c9732450..03f1c4902df 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RequestTokens.cs +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RequestTokens.cs @@ -23,8 +23,8 @@ public RequestTokens(IWorkContextAccessor workContextAccessor, IContentManager c public void Describe(DescribeContext context) { context.For("Request", T("Http Request"), T("Current Http Request tokens.")) - .Token("QueryString:*", T("QueryString:"), T("The Query String value for the specified element. If you want to chain text, surround the with brackets [e.g. QueryString:(param1)].")) - .Token("Form:*", T("Form:"), T("The Form value for the specified element. If you want to chain text, surround the with brackets [e.g. Form:(param1)].")) + .Token("QueryString:*", T("QueryString:"), T("The Query String value for the specified element. To chain text, surround the with parentheses, e.g. 'QueryString:(param1)'.")) + .Token("Form:*", T("Form:"), T("The Form value for the specified element. To chain text, surround the with parentheses, e.g. 'Form:(param1)'.")) .Token("Route:*", T("Route:"), T("The Route value for the specified key.")) .Token("Content", T("Content"), T("The request routed Content Item."), "Content") ; @@ -39,8 +39,8 @@ public void Evaluate(EvaluateContext context) { * 2. QueryString:param1 or Form:param1 * 3. QueryString:(param1).SomeOtherTextToken or Form:(param1).SomeOtherTextToken * - * If you want to Chain TextTokens you have to use 3rd syntax - * the element (here param1) has been surrounded with brackets in order to preserve backward compatibility. + * If you want to Chain TextTokens you have to use the 3rd syntax + * the element, here param1, has been surrounded with parentheses in order to preserve backward compatibility. */ context.For("Request", _workContextAccessor.GetContext().HttpContext.Request) .Token( From e3a7059edf212b6bffcafe2076f3da45487d0260 Mon Sep 17 00:00:00 2001 From: HermesSbicego-Laser Date: Fri, 28 Oct 2016 15:22:48 +0200 Subject: [PATCH 14/16] - Addition of an existing png (OrchardLogo.png) as attachment within "Test Smtp Settings" Section, in order to demonstrate functionality of support for attachments in email --- .../Orchard.Email/Controllers/EmailAdminController.cs | 8 +++++--- .../Views/EditorTemplates/Parts/SmtpSettings.cshtml | 4 ++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Email/Controllers/EmailAdminController.cs b/src/Orchard.Web/Modules/Orchard.Email/Controllers/EmailAdminController.cs index e5d64f49e5f..57bf23eacaa 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Controllers/EmailAdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Controllers/EmailAdminController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Web.Hosting; using System.Web.Mvc; using Orchard.ContentManagement; using Orchard.Email.Models; @@ -56,7 +57,8 @@ public ActionResult TestSettings(TestSmtpSettings testSettings) { {"Body", testSettings.Body}, {"ReplyTo", testSettings.ReplyTo}, {"Bcc", testSettings.Bcc}, - {"CC", testSettings.Cc} + {"CC", testSettings.Cc}, + { "Attachments", new List() { HostingEnvironment.MapPath("~/Media/OrchardLogo.png") } } }); } @@ -64,10 +66,10 @@ public ActionResult TestSettings(TestSmtpSettings testSettings) { return Json(new { error = fakeLogger.Message }); } - return Json(new {status = T("Message sent.").Text}); + return Json(new { status = T("Message sent.").Text }); } catch (Exception e) { - return Json(new {error = e.Message}); + return Json(new { error = e.Message }); } finally { var smtpChannelComponent = _smtpChannel as Component; diff --git a/src/Orchard.Web/Modules/Orchard.Email/Views/EditorTemplates/Parts/SmtpSettings.cshtml b/src/Orchard.Web/Modules/Orchard.Email/Views/EditorTemplates/Parts/SmtpSettings.cshtml index bc4c237d437..0bb06a132ad 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Views/EditorTemplates/Parts/SmtpSettings.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Email/Views/EditorTemplates/Parts/SmtpSettings.cshtml @@ -91,6 +91,10 @@
+
+ + @T( +
From 3c53ffb09a923c5eccf571f4f8be68c76de10d1f Mon Sep 17 00:00:00 2001 From: HermesSbicego-Laser Date: Fri, 4 Nov 2016 13:43:38 +0100 Subject: [PATCH 15/16] - replaced Regex.Replace with String.Trim(char[]) as suggested - ran Orchard.Tokens.Tests: 66/66 passed --- .../Modules/Orchard.Tokens/Providers/RequestTokens.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RequestTokens.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RequestTokens.cs index 03f1c4902df..5f472b6d28b 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RequestTokens.cs +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RequestTokens.cs @@ -129,12 +129,12 @@ private static string FilterTokenParam(string token) { chainIndex = token.IndexOf(").") + 1; tokenLength = (tokenPrefix + ":").Length; if (chainIndex == 0) {// ")." has not be found - return Regex.Replace(token.Substring(tokenLength), @"[\(|\)]", ""); + return token.Substring(tokenLength).Trim(new char[] { '(', ')' }); } if (!token.StartsWith((tokenPrefix + ":"), StringComparison.OrdinalIgnoreCase) || chainIndex <= tokenLength) { return null; } - return Regex.Replace(token.Substring(tokenLength, chainIndex - tokenLength), @"[\(|\)]", ""); + return token.Substring(tokenLength, chainIndex - tokenLength).Trim(new char[] { '(', ')' }); } private static Tuple FilterChainParam(string token) { string tokenPrefix; @@ -152,12 +152,12 @@ private static Tuple FilterChainParam(string token) { chainIndex = token.IndexOf(").") + 1; tokenLength = (tokenPrefix + ":").Length; if (chainIndex == 0) { // ")." has not be found - return new Tuple(Regex.Replace(token.Substring(tokenLength), @"[\(|\)]", ""), token.Length.ToString()); + return new Tuple(token.Substring(tokenLength).Trim(new char[] { '(', ')' }), token.Length.ToString()); } if (!token.StartsWith((tokenPrefix + ":"), StringComparison.OrdinalIgnoreCase) || chainIndex <= tokenLength) { return null; } - return new Tuple(Regex.Replace(token.Substring(tokenLength, chainIndex - tokenLength), @"[\(|\)]", ""), token.Substring(chainIndex + 1)); + return new Tuple(token.Substring(tokenLength, chainIndex - tokenLength).Trim(new char[] { '(', ')' }), token.Substring(chainIndex + 1)); } } From 14111a15ea6bbd5dec11867db1dcc5aea4cca153 Mon Sep 17 00:00:00 2001 From: "matteo.piovanelli" Date: Tue, 8 Nov 2016 12:20:16 +0100 Subject: [PATCH 16/16] Added a dropdown allowing language selection/filtering for the list of content items in the popup that appears when adding items to a ContentPickerField. This replicates the identical functionality from the List of content items. --- .../Controllers/AdminController.cs | 15 ++++++++++++++- .../Views/RecentContentTab.cshtml | 17 +++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.ContentPicker/Controllers/AdminController.cs index ca56791daa8..26e02fe50ae 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Controllers/AdminController.cs @@ -12,6 +12,7 @@ using Orchard.Core.Contents.ViewModels; using Orchard.DisplayManagement; using Orchard.Localization; +using Orchard.Localization.Services; using Orchard.Mvc; using Orchard.Settings; using Orchard.Themes; @@ -22,16 +23,22 @@ public class AdminController : Controller { private readonly ISiteService _siteService; private readonly IContentDefinitionManager _contentDefinitionManager; private readonly INavigationManager _navigationManager; + private readonly ICultureManager _cultureManager; + private readonly ICultureFilter _cultureFilter; public AdminController( IOrchardServices orchardServices, ISiteService siteService, IContentDefinitionManager contentDefinitionManager, - INavigationManager navigationManager) { + INavigationManager navigationManager, + ICultureManager cultureManager, + ICultureFilter cultureFilter) { _siteService = siteService; _contentDefinitionManager = contentDefinitionManager; _navigationManager = navigationManager; Services = orchardServices; + _cultureManager = cultureManager; + _cultureFilter = cultureFilter; T = NullLocalizer.Instance; } @@ -123,10 +130,16 @@ public ActionResult Index(ListContentsViewModel model, PagerParameters pagerPara break; } + if (!String.IsNullOrWhiteSpace(model.Options.SelectedCulture)) { + query = _cultureFilter.FilterCulture(query, model.Options.SelectedCulture); + } + model.Options.FilterOptions = contentTypes .Select(ctd => new KeyValuePair(ctd.Name, ctd.DisplayName)) .ToList().OrderBy(kvp => kvp.Value); + model.Options.Cultures = _cultureManager.ListCultures(); + var pagerShape = Services.New.Pager(pager).TotalItemCount(query.Count()); var pageOfContentItems = query.Slice(pager.GetStartIndex(), pager.PageSize).ToList(); var list = Services.New.List(); diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Views/RecentContentTab.cshtml b/src/Orchard.Web/Modules/Orchard.ContentPicker/Views/RecentContentTab.cshtml index 9d61fe6d74b..f16be6f46f0 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Views/RecentContentTab.cshtml +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Views/RecentContentTab.cshtml @@ -1,7 +1,7 @@ @using Orchard.Core.Contents.ViewModels; @{ Script.Require("SelectableContentTab"); - + var typeDisplayName = Model.TypeDisplayName; var pageTitle = T("Recent Content"); @@ -9,8 +9,10 @@ pageTitle = T("Manage {0} Content", typeDisplayName); } + IEnumerable cultures = Model.Options.Cultures; + Layout.Title = pageTitle; - + }
@@ -25,6 +27,17 @@ @Html.SelectOption((string)Model.Options.SelectedFilter, (string)filterOption.Key, (string)filterOption.Value) } + + @if (cultures.Count() > 1) { + + + } +