diff --git a/Perplex.Umbraco.Forms/App_Plugins/PerplexUmbracoForms/PerplexUmbracoForms.config b/Perplex.Umbraco.Forms/App_Plugins/PerplexUmbracoForms/PerplexUmbracoForms.config index 0e560b1..7b24969 100644 --- a/Perplex.Umbraco.Forms/App_Plugins/PerplexUmbracoForms/PerplexUmbracoForms.config +++ b/Perplex.Umbraco.Forms/App_Plugins/PerplexUmbracoForms/PerplexUmbracoForms.config @@ -44,4 +44,8 @@ + + true + 10 + \ No newline at end of file diff --git a/Perplex.Umbraco.Forms/Code/Configuration/ExtensionConfig.cs b/Perplex.Umbraco.Forms/Code/Configuration/ExtensionConfig.cs index 56f1479..e6f0014 100644 --- a/Perplex.Umbraco.Forms/Code/Configuration/ExtensionConfig.cs +++ b/Perplex.Umbraco.Forms/Code/Configuration/ExtensionConfig.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml.Serialization; +using System.Xml.Serialization; namespace PerplexUmbraco.Forms.Code.Configuration { diff --git a/Perplex.Umbraco.Forms/Code/Configuration/FieldTypeConfig.cs b/Perplex.Umbraco.Forms/Code/Configuration/FieldTypeConfig.cs index bf64c14..aff0b3a 100644 --- a/Perplex.Umbraco.Forms/Code/Configuration/FieldTypeConfig.cs +++ b/Perplex.Umbraco.Forms/Code/Configuration/FieldTypeConfig.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Xml.Serialization; namespace PerplexUmbraco.Forms.Code.Configuration diff --git a/Perplex.Umbraco.Forms/Code/Configuration/PerplexBaseFileConfig.cs b/Perplex.Umbraco.Forms/Code/Configuration/PerplexBaseFileConfig.cs index 8aa2867..4694db1 100644 --- a/Perplex.Umbraco.Forms/Code/Configuration/PerplexBaseFileConfig.cs +++ b/Perplex.Umbraco.Forms/Code/Configuration/PerplexBaseFileConfig.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; using System.Xml.Serialization; namespace PerplexUmbraco.Forms.Code.Configuration diff --git a/Perplex.Umbraco.Forms/Code/Configuration/PerplexCacheConfig.cs b/Perplex.Umbraco.Forms/Code/Configuration/PerplexCacheConfig.cs new file mode 100644 index 0000000..0d2a328 --- /dev/null +++ b/Perplex.Umbraco.Forms/Code/Configuration/PerplexCacheConfig.cs @@ -0,0 +1,14 @@ +using System.Xml.Serialization; + +namespace PerplexUmbraco.Forms.Code.Configuration +{ + [XmlType("PerplexCacheConfig")] + public class PerplexCacheConfig + { + [XmlElement("CacheDurationInMinutes")] + public int CacheDurationInMinutes { get; set; } + + [XmlElement("EnableCache")] + public bool EnableCache { get; set; } + } +} diff --git a/Perplex.Umbraco.Forms/Code/Configuration/PerplexFileUploadConfig.cs b/Perplex.Umbraco.Forms/Code/Configuration/PerplexFileUploadConfig.cs index 9f98e85..cd88ec5 100644 --- a/Perplex.Umbraco.Forms/Code/Configuration/PerplexFileUploadConfig.cs +++ b/Perplex.Umbraco.Forms/Code/Configuration/PerplexFileUploadConfig.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml.Serialization; +using System.Xml.Serialization; namespace PerplexUmbraco.Forms.Code.Configuration { diff --git a/Perplex.Umbraco.Forms/Code/Configuration/PerplexImageUploadConfig.cs b/Perplex.Umbraco.Forms/Code/Configuration/PerplexImageUploadConfig.cs index 5e9ad34..ebf9f3f 100644 --- a/Perplex.Umbraco.Forms/Code/Configuration/PerplexImageUploadConfig.cs +++ b/Perplex.Umbraco.Forms/Code/Configuration/PerplexImageUploadConfig.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml.Serialization; +using System.Xml.Serialization; namespace PerplexUmbraco.Forms.Code.Configuration { diff --git a/Perplex.Umbraco.Forms/Code/Configuration/PerplexRecaptchaConfig.cs b/Perplex.Umbraco.Forms/Code/Configuration/PerplexRecaptchaConfig.cs index 54477d9..cf76d3c 100644 --- a/Perplex.Umbraco.Forms/Code/Configuration/PerplexRecaptchaConfig.cs +++ b/Perplex.Umbraco.Forms/Code/Configuration/PerplexRecaptchaConfig.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml.Serialization; +using System.Xml.Serialization; namespace PerplexUmbraco.Forms.Code.Configuration { diff --git a/Perplex.Umbraco.Forms/Code/Configuration/PerplexUmbracoFormsConfig.cs b/Perplex.Umbraco.Forms/Code/Configuration/PerplexUmbracoFormsConfig.cs index 6c876da..27fc3ce 100644 --- a/Perplex.Umbraco.Forms/Code/Configuration/PerplexUmbracoFormsConfig.cs +++ b/Perplex.Umbraco.Forms/Code/Configuration/PerplexUmbracoFormsConfig.cs @@ -1,11 +1,9 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Web.Hosting; using System.Xml.Serialization; + using static PerplexUmbraco.Forms.Code.Constants; namespace PerplexUmbraco.Forms.Code.Configuration @@ -73,6 +71,8 @@ public static void CreateIfNotExists() public PerplexRecaptchaConfig PerplexRecaptchaConfig { get; set; } + public PerplexCacheConfig PerplexCacheConfig { get; set; } + private static string GetFilePath() { return HostingEnvironment.MapPath(Constants.CONFIGURATION_FILE_PATH); @@ -139,6 +139,12 @@ private static string GetFilePath() PerplexRecaptchaConfig = new PerplexRecaptchaConfig { ErrorMessage = "" + }, + + PerplexCacheConfig = new PerplexCacheConfig + { + EnableCache = false, + CacheDurationInMinutes = 10 } }; } diff --git a/Perplex.Umbraco.Forms/Code/UmbracoEvents.cs b/Perplex.Umbraco.Forms/Code/UmbracoEvents.cs index 69214d2..c223061 100644 --- a/Perplex.Umbraco.Forms/Code/UmbracoEvents.cs +++ b/Perplex.Umbraco.Forms/Code/UmbracoEvents.cs @@ -1,12 +1,14 @@ -using System.Linq; +using System; +using System.Linq; using System.Web; + +using PerplexUmbraco.Forms.Code.Configuration; + using Umbraco.Core; using Umbraco.Core.Logging; -using PerplexUmbraco.Forms.Code.Configuration; -using Umbraco.Web; -using Umbraco.Forms.Data.Storage; -using System; using Umbraco.Forms.Core; +using Umbraco.Forms.Data.Storage; +using Umbraco.Web; namespace PerplexUmbraco.Forms.Code { @@ -64,6 +66,8 @@ void FormStorage_Created(object sender, FormEventArgs e) folder.Forms.Add(form.Id.ToString()); PerplexFolder.SaveAll(); + + ClearFormsCache(folderId.ToString()); } void FormStorage_Deleted(object sender, FormEventArgs e) @@ -75,7 +79,23 @@ void FormStorage_Deleted(object sender, FormEventArgs e) { folder.Forms.Remove(form.Id.ToString()); PerplexFolder.SaveAll(); + + ClearFormsCache(folder.Id); + } + } + + void ClearFormsCache(string folderId) + { + var cacheConfig = PerplexUmbracoFormsConfig.Get.PerplexCacheConfig; + + if (cacheConfig.EnableCache) + { + var cacheKey = $"PerplexFormTreeController_GetTreeNodes_id:{folderId}"; + var rtCache = ApplicationContext.Current.ApplicationCache.RuntimeCache; + + if (rtCache.GetCacheItemsByKeySearch(cacheKey).Any()) + rtCache.ClearCacheByKeySearch(cacheKey); } } } -} \ No newline at end of file +} diff --git a/Perplex.Umbraco.Forms/Controllers/PerplexFormTreeController.cs b/Perplex.Umbraco.Forms/Controllers/PerplexFormTreeController.cs index 7ee2956..d77ce79 100644 --- a/Perplex.Umbraco.Forms/Controllers/PerplexFormTreeController.cs +++ b/Perplex.Umbraco.Forms/Controllers/PerplexFormTreeController.cs @@ -1,23 +1,18 @@ -using Newtonsoft.Json; -using PerplexUmbraco.Forms.Code; -using System; -using System.Collections.Generic; -using System.IO; +using System; using System.Linq; using System.Net.Http.Formatting; -using System.Text; -using System.Threading.Tasks; using System.Web; -using System.Web.Hosting; -using System.Web.Http; -using Umbraco.Forms.Data; + +using PerplexUmbraco.Forms.Code; +using PerplexUmbraco.Forms.Code.Configuration; + +using umbraco; +using umbraco.BusinessLogic.Actions; using Umbraco.Forms.Web.Trees; +using Umbraco.Web; using Umbraco.Web.Models.Trees; using Umbraco.Web.Mvc; using Umbraco.Web.Trees; -using Umbraco.Web; -using umbraco.BusinessLogic.Actions; -using umbraco; namespace PerplexUmbraco.Forms.Controllers { @@ -41,27 +36,61 @@ public class PerplexFormTreeController : FormTreeController { // We load our custom menu actions from our own folder private const string VIEWS_ROOT = "/App_Plugins/PerplexUmbracoForms/views/"; + private readonly PerplexCacheConfig _cacheConfig; - public PerplexFormTreeController() { } + public PerplexFormTreeController() + { + _cacheConfig = PerplexUmbracoFormsConfig.Get.PerplexCacheConfig; + } - protected override Umbraco.Web.Models.Trees.TreeNodeCollection GetTreeNodes(string id, System.Net.Http.Formatting.FormDataCollection queryStrings) + protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings) { + var cacheKey = $"PerplexFormTreeController_GetTreeNodes_id:{queryStrings["id"]}"; + var rtCache = ApplicationContext.ApplicationCache.RuntimeCache; + // If this is a form, use Umbraco's default behavior var folder = PerplexFolder.Get(id); if (folder == null) { - return base.GetTreeNodes(id, queryStrings); + var treeNodeCollection = _cacheConfig.EnableCache ? (TreeNodeCollection)rtCache.GetCacheItem(cacheKey) : (TreeNodeCollection)null; + + if (treeNodeCollection == null) + { + treeNodeCollection = base.GetTreeNodes(id, queryStrings); + + if (_cacheConfig.EnableCache) + { + if (rtCache.GetCacheItemsByKeySearch(cacheKey).Any()) + rtCache.ClearCacheByKeySearch(cacheKey); + + rtCache.InsertCacheItem(cacheKey, () => treeNodeCollection, new TimeSpan(0, _cacheConfig.CacheDurationInMinutes, 0), true); + } + } + + return treeNodeCollection; } // This is a folder + var baseTreeNodes = _cacheConfig.EnableCache ? (TreeNodeCollection)rtCache.GetCacheItem(cacheKey) : (TreeNodeCollection)null; + + if (baseTreeNodes == null) + { + // We require all forms, and apply filtering based on folders later + baseTreeNodes = base.GetTreeNodes("-1", queryStrings); - // We require all forms, and apply filtering based on folders later - var baseTreeNodes = base.GetTreeNodes("-1", queryStrings); + if (_cacheConfig.EnableCache) + { + if (rtCache.GetCacheItemsByKeySearch(cacheKey).Any()) + rtCache.ClearCacheByKeySearch(cacheKey); + + rtCache.InsertCacheItem(cacheKey, () => baseTreeNodes, new TimeSpan(0, _cacheConfig.CacheDurationInMinutes, 0), true); + } + } // Sanity check; make sure there are no orphan forms around // (forms not contained within any folder). If so, move them to the root folder var orphans = baseTreeNodes.Where(n => PerplexFolder.Get(f => f.Forms.Any(formId => formId == n.Id.ToString())) == null).ToList(); - if(orphans.Count > 0) + if (orphans.Count > 0) { foreach (var orphan in orphans) { @@ -74,7 +103,7 @@ protected override Umbraco.Web.Models.Trees.TreeNodeCollection GetTreeNodes(stri // Hide all Forms that are not contained within this folder // If this folder itself is disabled (due to the user not having access), // we also hide all its forms - baseTreeNodes.RemoveAll(n => + baseTreeNodes.RemoveAll(n => !folder.Forms.Contains(n.Id.ToString()) || (folder.Disabled && folder.Forms.Contains(n.Id.ToString())) ); @@ -92,7 +121,7 @@ protected override Umbraco.Web.Models.Trees.TreeNodeCollection GetTreeNodes(stri // Add any subfolders of this node // We loop through the list in reverse as we add every folder at the start of the list (before forms) - foreach (var subFolder in folder.Folders.Reverse()) + foreach (var subFolder in folder.Folders.Reverse()) { // If this subfolder is disabled, and it is not on a path towards // a folder that is NOT disabled, it should not be listed at all. @@ -139,7 +168,7 @@ protected override TreeNode CreateRootNode(FormDataCollection queryStrings) // If none are set, all folders are allowed so we just use default behavior // Likewise if the common ancestors of all allowed folders is the root. - PerplexFolder commonAncestor = PerplexFolder.GetCommonAncestor(startFolders); + PerplexFolder commonAncestor = PerplexFolder.GetCommonAncestor(startFolders); if (!startFolders.Any() || commonAncestor == PerplexFolder.GetRootFolder()) { @@ -157,11 +186,11 @@ protected override TreeNode CreateRootNode(FormDataCollection queryStrings) // if this is the common ancestor of this user's start nodes but not // a start node itself. In that case it should also show as disabled in // the UI, and we hide its URL. - rootNode.RoutePath = "forms/perplexForms/folder/" + commonAncestor.Id; - if(commonAncestor.Disabled) + rootNode.RoutePath = "forms/perplexForms/folder/" + commonAncestor.Id; + if (commonAncestor.Disabled) { rootNode.CssClasses.Add("disabled"); - } + } // Folder has children if it has either forms or folders rootNode.HasChildren = commonAncestor.Forms.Any() || commonAncestor.Folders.Any(); @@ -197,10 +226,10 @@ protected override MenuItemCollection GetMenuForNode(string id, FormDataCollecti { menu.Items.RemoveAll(m => m.Alias != ActionRefresh.Instance.Alias); return menu; - } + } // Create Form (default Umbraco view, hence alias) - AddMenuItem(menu, "Create Form", alias: "create", icon: "icon icon-add"); + AddMenuItem(menu, "Create Form", alias: "create", icon: "icon icon-add"); // Create Folder AddMenuItem(menu, "Create Folder", view: "createFolder", icon: "icon icon-folder"); @@ -239,7 +268,7 @@ protected override MenuItemCollection GetMenuForNode(string id, FormDataCollecti var root = PerplexFolder.GetRootFolder(); // If the root folder is disabled, remove all menu actions except Reload - if(root.Disabled) + if (root.Disabled) { menu.Items.RemoveAll(m => m.Alias != ActionRefresh.Instance.Alias); return menu; diff --git a/Perplex.Umbraco.Forms/Controllers/PerplexUmbracoFormController.cs b/Perplex.Umbraco.Forms/Controllers/PerplexUmbracoFormController.cs index 19aa2b9..198af4f 100644 --- a/Perplex.Umbraco.Forms/Controllers/PerplexUmbracoFormController.cs +++ b/Perplex.Umbraco.Forms/Controllers/PerplexUmbracoFormController.cs @@ -1,23 +1,15 @@ -using Newtonsoft.Json; -using PerplexUmbraco.Forms.Code; -using PerplexUmbraco.Forms.Code.Configuration; -using System; +using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Web; -using System.Web.Hosting; using System.Web.Http; -using Umbraco.Core.IO; -using Umbraco.Forms.Core.Providers; -using Umbraco.Forms.Data; + +using PerplexUmbraco.Forms.Code; +using PerplexUmbraco.Forms.Code.Configuration; + using Umbraco.Forms.Data.Storage; -using Umbraco.Forms.Mvc.Models.Backoffice; -using Umbraco.Forms.Web.Models.Backoffice; -using Umbraco.Web.Editors; -using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; namespace PerplexUmbraco.Forms.Controllers diff --git a/Perplex.Umbraco.Forms/Perplex.Umbraco.Forms.csproj b/Perplex.Umbraco.Forms/Perplex.Umbraco.Forms.csproj index 23d0741..1409be6 100644 --- a/Perplex.Umbraco.Forms/Perplex.Umbraco.Forms.csproj +++ b/Perplex.Umbraco.Forms/Perplex.Umbraco.Forms.csproj @@ -230,6 +230,7 @@ +