From 69b0c7cf099d450b775c0452cfbe92d87d3aea29 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Fri, 29 Mar 2013 15:01:04 -0100 Subject: [PATCH 01/16] Fixes: U4-2024 Umbraco 6.0.3 : Error while importing Document Type --- src/Umbraco.Core/Services/PackagingService.cs | 2 +- .../dialogs/importDocumenttype.aspx.cs | 23 ++++++++----------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/Umbraco.Core/Services/PackagingService.cs b/src/Umbraco.Core/Services/PackagingService.cs index ac651f675f..6245c2a31f 100644 --- a/src/Umbraco.Core/Services/PackagingService.cs +++ b/src/Umbraco.Core/Services/PackagingService.cs @@ -209,7 +209,7 @@ namespace Umbraco.Core.Services _importedContentTypes = new Dictionary(); var documentTypes = name.Equals("DocumentTypes") ? (from doc in element.Elements("DocumentType") select doc).ToList() - : new List {element.Element("DocumentType")}; + : new List {element}; //NOTE it might be an idea to sort the doctype XElements based on dependencies //before creating the doc types - should also allow for a better structure/inheritance support. foreach (var documentType in documentTypes) diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/importDocumenttype.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/importDocumenttype.aspx.cs index 18eccdaaf1..aec5421174 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/importDocumenttype.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/importDocumenttype.aspx.cs @@ -5,7 +5,7 @@ using System.Web.UI.HtmlControls; using System.Xml; using System.Xml.Linq; using Umbraco.Core; -using umbraco.IO; +using Umbraco.Core.IO; namespace umbraco.presentation.umbraco.dialogs { @@ -69,12 +69,10 @@ namespace umbraco.presentation.umbraco.dialogs private void import_Click(object sender, EventArgs e) { - /*XmlDocument xd = new XmlDocument(); - xd.Load(tempFile.Value); - cms.businesslogic.packager.Installer.ImportDocumentType(xd.DocumentElement, base.getUser(), true); - dtNameConfirm.Text = xd.DocumentElement.SelectSingleNode("/DocumentType/Info/Name").FirstChild.Value;*/ + var xd = new XmlDocument(); + xd.Load(tempFile.Value); - var element = XElement.Parse(tempFile.Value); + var element = XElement.Parse(xd.InnerXml); var importContentTypes = ApplicationContext.Current.Services.PackagingService.ImportContentTypes(element); var contentType = importContentTypes.FirstOrDefault(); if (contentType != null) @@ -85,25 +83,22 @@ namespace umbraco.presentation.umbraco.dialogs done.Visible = true; } - private void submit_Click(object sender, System.EventArgs e) + private void submit_Click(object sender, EventArgs e) { tempFileName = "justDelete_" + Guid.NewGuid().ToString() + ".udt"; - string fileName = IOHelper.MapPath(SystemDirectories.Data + "/" + tempFileName); + var fileName = IOHelper.MapPath(SystemDirectories.Data + "/" + tempFileName); tempFile.Value = fileName; documentTypeFile.PostedFile.SaveAs(fileName); - XmlDocument xd = new XmlDocument(); + var xd = new XmlDocument(); xd.Load(fileName); - dtName.Text = xd.DocumentElement.SelectSingleNode("/DocumentType/Info/Name").FirstChild.Value; - dtAlias.Text = xd.DocumentElement.SelectSingleNode("/DocumentType/Info/Alias").FirstChild.Value; - + dtName.Text = xd.DocumentElement.SelectSingleNode("//DocumentType/Info/Name").FirstChild.Value; + dtAlias.Text = xd.DocumentElement.SelectSingleNode("//DocumentType/Info/Alias").FirstChild.Value; Wizard.Visible = false; done.Visible = false; Confirm.Visible = true; - } - } } From 55c7f72d8e8dbd74b42baecaa1ed62842a41d972 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Fri, 29 Mar 2013 23:14:42 +0600 Subject: [PATCH 02/16] Converts create.aspx to have the correct webforms file/class structure, fixed logging for userTask, fixed issue with last regex fix for xss --- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 7 +++ src/Umbraco.Web.UI/umbraco/Create.aspx.cs | 44 +++++++++++++++ .../umbraco/Create.aspx.designer.cs} | 11 ++-- src/Umbraco.Web.UI/umbraco/create.aspx | 9 +++- .../Application/HistoryManager.js | 2 +- src/Umbraco.Web/Umbraco.Web.csproj | 17 +++--- .../umbraco.presentation/umbraco/create.aspx | 38 ------------- .../umbraco/create.aspx.cs | 53 +++++++------------ .../umbraco/create/userTasks.cs | 43 ++++----------- 9 files changed, 99 insertions(+), 125 deletions(-) create mode 100644 src/Umbraco.Web.UI/umbraco/Create.aspx.cs rename src/{Umbraco.Web/umbraco.presentation/umbraco/create.aspx.designer.cs => Umbraco.Web.UI/umbraco/Create.aspx.designer.cs} (70%) delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/create.aspx diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 0b57950ed3..b9974b8334 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -289,6 +289,13 @@ loadStarterKits.ascx + + create.aspx + ASPXCodeBehind + + + create.aspx + editMacro.aspx ASPXCodeBehind diff --git a/src/Umbraco.Web.UI/umbraco/Create.aspx.cs b/src/Umbraco.Web.UI/umbraco/Create.aspx.cs new file mode 100644 index 0000000000..b30e2a3f3b --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/Create.aspx.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Xml; +using Umbraco.Core; +using Umbraco.Core.IO; +using umbraco.cms.presentation.Trees; + +namespace Umbraco.Web.UI.Umbraco +{ + public partial class Create : global::umbraco.cms.presentation.Create + { + + //protected override void OnLoad(EventArgs e) + //{ + // if (SecurityCheck(Request.QueryString["nodeType"])) + // { + // //if we're allowed, then continue + // base.OnLoad(e); + // } + // else + // { + // //otherwise show an error + // UI.Visible = false; + // AccessError.Visible = true; + // } + //} + + //private bool SecurityCheck(string treeAlias) + //{ + // var tree = TreeDefinitionCollection.Instance.FindTree(treeAlias); + // if (tree != null) + // { + // //does the current user have access to the current app? + // var user = this.getUser(); + // var userApps = user.Applications; + // return userApps.Any(x => x.alias.InvariantEquals(tree.App.alias)); + // } + // return false; + //} + + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create.aspx.designer.cs b/src/Umbraco.Web.UI/umbraco/Create.aspx.designer.cs similarity index 70% rename from src/Umbraco.Web/umbraco.presentation/umbraco/create.aspx.designer.cs rename to src/Umbraco.Web.UI/umbraco/Create.aspx.designer.cs index a3d4616bfd..12722853d4 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create.aspx.designer.cs +++ b/src/Umbraco.Web.UI/umbraco/Create.aspx.designer.cs @@ -1,25 +1,24 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.3053 // // Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. +// the code is regenerated. // //------------------------------------------------------------------------------ -namespace umbraco.cms.presentation { +namespace Umbraco.Web.UI.Umbraco { public partial class Create { /// - /// UI control. + /// AccessError control. /// /// /// Auto-generated field. /// To modify move field declaration from designer file to code-behind file. /// - protected global::System.Web.UI.WebControls.PlaceHolder UI; + protected global::System.Web.UI.WebControls.PlaceHolder AccessError; } } diff --git a/src/Umbraco.Web.UI/umbraco/create.aspx b/src/Umbraco.Web.UI/umbraco/create.aspx index 8bcc0cacb9..ba4b091eda 100644 --- a/src/Umbraco.Web.UI/umbraco/create.aspx +++ b/src/Umbraco.Web.UI/umbraco/create.aspx @@ -1,4 +1,4 @@ -<%@ Page Language="c#" MasterPageFile="masterpages/umbracoDialog.Master" Codebehind="create.aspx.cs" AutoEventWireup="True" Inherits="umbraco.cms.presentation.Create" %> +<%@ Page Language="c#" MasterPageFile="masterpages/umbracoDialog.Master" Codebehind="Create.aspx.cs" AutoEventWireup="True" Inherits="Umbraco.Web.UI.Umbraco.Create" %> <%@ Register Namespace="umbraco" TagPrefix="umb" Assembly="umbraco" %> @@ -18,6 +18,13 @@ + +
+

+ The current user does not have access to create this type of object +

+
+
diff --git a/src/Umbraco.Web.UI/umbraco_client/Application/HistoryManager.js b/src/Umbraco.Web.UI/umbraco_client/Application/HistoryManager.js index b1f44a8f46..bed8630cf5 100644 --- a/src/Umbraco.Web.UI/umbraco_client/Application/HistoryManager.js +++ b/src/Umbraco.Web.UI/umbraco_client/Application/HistoryManager.js @@ -13,7 +13,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls"); function getHashFragment(frag) { //tests for xss and ensures only the first alphanumeric chars are matched var result = hashFragmentRegex.exec(frag); - if (result.length > 0) { + if (result != null && result.length > 0) { return result[0]; } return ""; diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 02045b1eaa..89351a42c1 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -342,6 +342,9 @@ + + ASPXCodeBehind + ASPXCodeBehind @@ -980,13 +983,6 @@ SendPublish.aspx - - create.aspx - ASPXCodeBehind - - - create.aspx - content.ascx ASPXCodeBehind @@ -1935,7 +1931,9 @@ ASPXCodeBehind - + + ASPXCodeBehind + @@ -2006,9 +2004,6 @@ - - ASPXCodeBehind - ASPXCodeBehind diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create.aspx b/src/Umbraco.Web/umbraco.presentation/umbraco/create.aspx deleted file mode 100644 index 8bcc0cacb9..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create.aspx +++ /dev/null @@ -1,38 +0,0 @@ -<%@ Page Language="c#" MasterPageFile="masterpages/umbracoDialog.Master" Codebehind="create.aspx.cs" AutoEventWireup="True" Inherits="umbraco.cms.presentation.Create" %> - -<%@ Register Namespace="umbraco" TagPrefix="umb" Assembly="umbraco" %> - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create.aspx.cs index 764428c664..9555996f59 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create.aspx.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.ComponentModel; using System.Data; @@ -11,33 +11,34 @@ using System.Web.UI.HtmlControls; using System.Xml.XPath; using System.Xml; -using umbraco.IO; +using Umbraco.Core.IO; namespace umbraco.cms.presentation { - /// - /// Summary description for create. - /// - public partial class Create : BasePages.UmbracoEnsuredPage + + public class Create : BasePages.UmbracoEnsuredPage { protected umbWindow createWindow; - protected System.Web.UI.WebControls.Label helpText; - protected System.Web.UI.WebControls.TextBox rename; - protected System.Web.UI.WebControls.Label Label1; - protected System.Web.UI.WebControls.ListBox nodeType; + protected Label helpText; + protected TextBox rename; + protected Label Label1; + protected ListBox nodeType; + protected PlaceHolder UI; - protected void Page_Load(object sender, System.EventArgs e) + protected override void OnLoad(EventArgs e) { - // Load create definitions - string nodeType = Request.QueryString["nodeType"]; + base.OnLoad(e); - XmlDocument createDef = new XmlDocument(); - XmlTextReader defReader = new XmlTextReader(IOHelper.MapPath(SystemFiles.CreateUiXml)); + // Load create definitions + var nodeType = Request.QueryString["nodeType"]; + + var createDef = new XmlDocument(); + var defReader = new XmlTextReader(IOHelper.MapPath(SystemFiles.CreateUiXml)); createDef.Load(defReader); defReader.Close(); // Find definition for current nodeType - XmlNode def = createDef.SelectSingleNode("//nodeType [@alias = '" + nodeType + "']"); + var def = createDef.SelectSingleNode("//nodeType [@alias = '" + nodeType + "']"); if (def == null) { throw new ArgumentException("The create dialog for \"" + nodeType + "\" does not match anything defined in the \"" + SystemFiles.CreateUiXml + "\". This could mean an incorrectly installed package or a corrupt UI file"); @@ -46,7 +47,7 @@ namespace umbraco.cms.presentation try { //headerTitle.Text = title.Text; - UI.Controls.Add(new UserControl().LoadControl(SystemDirectories.Umbraco + def.SelectSingleNode("./usercontrol").FirstChild.Value)); + UI.Controls.Add(LoadControl(SystemDirectories.Umbraco + def.SelectSingleNode("./usercontrol").FirstChild.Value)); } catch (Exception ex) { @@ -54,24 +55,6 @@ namespace umbraco.cms.presentation } } - #region Web Form Designer generated code - override protected void OnInit(EventArgs e) - { - // - // CODEGEN: This call is required by the ASP.NET Web Form Designer. - // - InitializeComponent(); - base.OnInit(e); - } - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - - } - #endregion } } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/userTasks.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/userTasks.cs index 050f0aade2..e169d1ee8e 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/userTasks.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create/userTasks.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.Web.Security; +using Umbraco.Core.Logging; using umbraco.BusinessLogic; using umbraco.DataLayer; using umbraco.BasePages; @@ -11,35 +12,19 @@ namespace umbraco { public class userTasks : interfaces.ITaskReturnUrl { - - private string _alias; - private int _parentID; - private int _typeID; - private int _userID; private string _returnUrl = ""; public int UserId { - set { _userID = value; } - } - public int TypeID - { - set { _typeID = value; } - get { return _typeID; } + set { } } + public int TypeID { get; set; } - public string Alias - { - set { _alias = value; } - get { return _alias; } - } - public int ParentID - { - set { _parentID = value; } - get { return _parentID; } - } + public string Alias { get; set; } + + public int ParentID { get; set; } public string ReturnUrl { @@ -53,11 +38,11 @@ namespace umbraco //BusinessLogic.User.MakeNew(Alias, Alias, "", BusinessLogic.UserType.GetUserType(1)); //return true; - MembershipCreateStatus status = MembershipCreateStatus.ProviderError; + var status = MembershipCreateStatus.ProviderError; try { // Password is auto-generated. They are they required to change the password by editing the user information. - MembershipUser u = Membership.Providers[UmbracoSettings.DefaultBackofficeProvider].CreateUser(Alias, + var u = Membership.Providers[UmbracoSettings.DefaultBackofficeProvider].CreateUser(Alias, Membership.GeneratePassword( Membership.Providers[UmbracoSettings.DefaultBackofficeProvider].MinRequiredPasswordLength, Membership.Providers[UmbracoSettings.DefaultBackofficeProvider].MinRequiredNonAlphanumericCharacters), @@ -69,24 +54,16 @@ namespace umbraco } catch (Exception ex) { - Log.Add(LogTypes.Error, ParentID, String.Format("Failed to create the user. Error from provider: {0}", status.ToString())); - Log.Add(LogTypes.Debug, ParentID, ex.Message); + LogHelper.Error(string.Format("Failed to create the user. Error from provider: {0}", status.ToString()), ex); return false; } } public bool Delete() { - BusinessLogic.User u = BusinessLogic.User.GetUser(ParentID); + var u = User.GetUser(ParentID); u.disable(); return true; } - - public userTasks() - { - // - // TODO: Add constructor logic here - // - } } } From 13e555f50b1eff0a2ed8d8aa8570a84efb83002b Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Fri, 29 Mar 2013 23:52:40 +0600 Subject: [PATCH 03/16] Fixed merge issue based on overlap with class + namespace name. --- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 16 ++++++++-------- src/Umbraco.Web.UI/umbraco/Create.aspx.cs | 2 +- .../umbraco/Create.aspx.designer.cs | 7 ++++--- src/Umbraco.Web.UI/umbraco/create.aspx | 2 +- src/Umbraco.Web/Umbraco.Web.csproj | 2 +- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 65aa2af623..4e57b2aaa1 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -277,13 +277,6 @@ loadStarterKits.ascx - - PartialViewMacro.ascx - ASPXCodeBehind - - - PartialViewMacro.ascx - create.aspx ASPXCodeBehind @@ -291,6 +284,13 @@ create.aspx + + PartialViewMacro.ascx + ASPXCodeBehind + + + PartialViewMacro.ascx + editMacro.aspx ASPXCodeBehind @@ -434,6 +434,7 @@ + @@ -1913,7 +1914,6 @@ - UserControl diff --git a/src/Umbraco.Web.UI/umbraco/Create.aspx.cs b/src/Umbraco.Web.UI/umbraco/Create.aspx.cs index b30e2a3f3b..204285f180 100644 --- a/src/Umbraco.Web.UI/umbraco/Create.aspx.cs +++ b/src/Umbraco.Web.UI/umbraco/Create.aspx.cs @@ -9,7 +9,7 @@ using umbraco.cms.presentation.Trees; namespace Umbraco.Web.UI.Umbraco { - public partial class Create : global::umbraco.cms.presentation.Create + public partial class CreateDialog : global::umbraco.cms.presentation.Create { //protected override void OnLoad(EventArgs e) diff --git a/src/Umbraco.Web.UI/umbraco/Create.aspx.designer.cs b/src/Umbraco.Web.UI/umbraco/Create.aspx.designer.cs index 12722853d4..1e11eaf00d 100644 --- a/src/Umbraco.Web.UI/umbraco/Create.aspx.designer.cs +++ b/src/Umbraco.Web.UI/umbraco/Create.aspx.designer.cs @@ -8,9 +8,10 @@ //------------------------------------------------------------------------------ namespace Umbraco.Web.UI.Umbraco { - - - public partial class Create { + + + public partial class CreateDialog + { /// /// AccessError control. diff --git a/src/Umbraco.Web.UI/umbraco/create.aspx b/src/Umbraco.Web.UI/umbraco/create.aspx index ba4b091eda..2b112f516b 100644 --- a/src/Umbraco.Web.UI/umbraco/create.aspx +++ b/src/Umbraco.Web.UI/umbraco/create.aspx @@ -1,4 +1,4 @@ -<%@ Page Language="c#" MasterPageFile="masterpages/umbracoDialog.Master" Codebehind="Create.aspx.cs" AutoEventWireup="True" Inherits="Umbraco.Web.UI.Umbraco.Create" %> +<%@ Page Language="c#" MasterPageFile="masterpages/umbracoDialog.Master" Codebehind="CreateDialog.aspx.cs" AutoEventWireup="True" Inherits="Umbraco.Web.UI.Umbraco.CreateDialog" %> <%@ Register Namespace="umbraco" TagPrefix="umb" Assembly="umbraco" %> diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 506ef84d73..388e45eb4f 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -359,9 +359,9 @@ ASPXCodeBehind + - ASPXCodeBehind From 49b5ddf850533589dbe01cd808a461f3b3bbb104 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Sun, 31 Mar 2013 18:17:01 -0200 Subject: [PATCH 04/16] Refactor of fix for U4-2014 --- src/Umbraco.Core/Services/PackagingService.cs | 13 +- src/Umbraco.Core/TopologicalSorter.cs | 10 +- .../Importing/ImportResources.Designer.cs | 27 ++ .../Services/Importing/ImportResources.resx | 3 + .../Services/Importing/PackageImportTests.cs | 18 ++ .../Services/Importing/XsltSearch-Package.xml | 254 ++++++++++++++++++ src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + 7 files changed, 323 insertions(+), 3 deletions(-) create mode 100644 src/Umbraco.Tests/Services/Importing/XsltSearch-Package.xml diff --git a/src/Umbraco.Core/Services/PackagingService.cs b/src/Umbraco.Core/Services/PackagingService.cs index 6245c2a31f..1c93a4f56d 100644 --- a/src/Umbraco.Core/Services/PackagingService.cs +++ b/src/Umbraco.Core/Services/PackagingService.cs @@ -580,8 +580,19 @@ namespace Umbraco.Core.Services foreach (XElement tempElement in templateElements) { var dependencies = new List(); - if(tempElement.Element("Master") != null && string.IsNullOrEmpty(tempElement.Element("Master").Value) == false) + if (tempElement.Element("Master") != null && + string.IsNullOrEmpty(tempElement.Element("Master").Value) == false && + templateElements.Any(x => x.Element("Alias").Value == tempElement.Element("Master").Value)) + { dependencies.Add(tempElement.Element("Master").Value); + } + else if (tempElement.Element("Master") != null && + string.IsNullOrEmpty(tempElement.Element("Master").Value) == false && + templateElements.Any(x => x.Element("Alias").Value == tempElement.Element("Master").Value) == + false) + { + LogHelper.Info(string.Format("Template '{0}' has an invalid Master '{1}', so the reference has been ignored.", tempElement.Element("Alias").Value, tempElement.Element("Master").Value)); + } var field = new TopologicalSorter.DependencyField { diff --git a/src/Umbraco.Core/TopologicalSorter.cs b/src/Umbraco.Core/TopologicalSorter.cs index b62628538a..436a247f5e 100644 --- a/src/Umbraco.Core/TopologicalSorter.cs +++ b/src/Umbraco.Core/TopologicalSorter.cs @@ -139,9 +139,15 @@ namespace Umbraco.Core { if (fields[i].DependsOn != null) { - foreach (string t in fields[i].DependsOn.Where(t => indexes.ContainsKey(t.ToLowerInvariant()))) + for (int j = 0; j < fields[i].DependsOn.Length; j++) { - g.AddEdge(i,indexes[t.ToLowerInvariant()]); + if (indexes.ContainsKey(fields[i].DependsOn[j].ToLowerInvariant()) == false) + throw new IndexOutOfRangeException( + string.Format( + "The alias '{0}' has an invalid dependency. The dependency '{1}' does not exist in the list of aliases", + fields[i], fields[i].DependsOn[j])); + + g.AddEdge(i, indexes[fields[i].DependsOn[j].ToLowerInvariant()]); } } } diff --git a/src/Umbraco.Tests/Services/Importing/ImportResources.Designer.cs b/src/Umbraco.Tests/Services/Importing/ImportResources.Designer.cs index fe580b782b..a465d0762a 100644 --- a/src/Umbraco.Tests/Services/Importing/ImportResources.Designer.cs +++ b/src/Umbraco.Tests/Services/Importing/ImportResources.Designer.cs @@ -136,5 +136,32 @@ namespace Umbraco.Tests.Services.Importing { return ResourceManager.GetString("uBlogsy_Package", resourceCulture); } } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files> + /// <file> + /// <guid>XSLTsearch.xslt</guid> + /// <orgPath>/xslt</orgPath> + /// <orgName>XSLTsearch.xslt</orgName> + /// </file> + /// <file> + /// <guid>XSLTsearch.cs</guid> + /// <orgPath>/App_Code</orgPath> + /// <orgName>XSLTsearch.cs</orgName> + /// </file> + /// </files> + /// <info> + /// <package> + /// <name>XSLTsearch</name> + /// <version>3.0.4</version> + /// <license url="http://www.opensource.org/licenses/mit-li [rest of string was truncated]";. + /// + internal static string XsltSearch_Package { + get { + return ResourceManager.GetString("XsltSearch_Package", resourceCulture); + } + } } } diff --git a/src/Umbraco.Tests/Services/Importing/ImportResources.resx b/src/Umbraco.Tests/Services/Importing/ImportResources.resx index 6fd3b9cf87..cc7d59a7eb 100644 --- a/src/Umbraco.Tests/Services/Importing/ImportResources.resx +++ b/src/Umbraco.Tests/Services/Importing/ImportResources.resx @@ -127,4 +127,7 @@ ublogsy-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + xsltsearch-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + \ No newline at end of file diff --git a/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs b/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs index 287ebd0c94..5dc1a697a2 100644 --- a/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs +++ b/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs @@ -188,5 +188,23 @@ namespace Umbraco.Tests.Services.Importing Assert.That(contents.Any(), Is.True); Assert.That(contents.Count(), Is.EqualTo(numberOfDocs)); } + + [Test] + public void PackagingService_Can_Import_Templates_Package_Xml_With_Invalid_Master() + { + // Arrange + string strXml = ImportResources.XsltSearch_Package; + var xml = XElement.Parse(strXml); + var templateElement = xml.Descendants("Templates").First(); + var packagingService = ServiceContext.PackagingService; + + // Act + var templates = packagingService.ImportTemplates(templateElement); + var numberOfTemplates = (from doc in templateElement.Elements("Template") select doc).Count(); + + // Assert + Assert.That(templates.Any(), Is.True); + Assert.That(templates.Count(), Is.EqualTo(numberOfTemplates)); + } } } \ No newline at end of file diff --git a/src/Umbraco.Tests/Services/Importing/XsltSearch-Package.xml b/src/Umbraco.Tests/Services/Importing/XsltSearch-Package.xml new file mode 100644 index 0000000000..8096cfb833 --- /dev/null +++ b/src/Umbraco.Tests/Services/Importing/XsltSearch-Package.xml @@ -0,0 +1,254 @@ + + + + + XSLTsearch.xslt + /xslt + XSLTsearch.xslt + + + XSLTsearch.cs + /App_Code + XSLTsearch.cs + + + + + XSLTsearch + 3.0.4 + MIT license + http://www.percipientstudios.com + + 3 + 0 + 0 + + + + Percipient Studios + http://www.percipientstudios.com + + + + + + + + + 0 + + + + + + + XSLTsearch + XSLTsearch + .sprTreeDoc2 + doc.png + + XSLTsearch page. + (adjust settings via the macro in the XSLTsearch template) + + + + + XSLTsearch + + + + + Hide in navigation + umbracoNaviHide + 38b352c1-e9f8-4fd8-9324-9a2eab06d97a + 92897bc6-a5f3-4ffe-ae27-f2e7e33dda49 + + + False + + + + + + + + + + + + + + XSLTsearch + + + + + + + + + + XSLTsearch + XSLTsearch + + + + + XSLTsearch.xslt + False + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ]]> + + + + + \ No newline at end of file diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 2d4f87535c..ad98224325 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -430,6 +430,7 @@ Designer + From ff337457f8f2a9f31c78db30df37bc082fe22535 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 1 Apr 2013 11:31:03 -0200 Subject: [PATCH 05/16] Fixes: U4-662 Most icon for document type can't be shown in 4.8.1. --- .../Configuration/UmbracoSettings.cs | 35 ++++ src/Umbraco.Core/IconPickerBehaviour.cs | 24 +++ src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../config/umbracoSettings.Release.config | 18 ++- .../config/umbracoSettings.config | 16 +- .../umbraco_client/ui/jquery.dd.js | 41 +++-- .../controls/ContentTypeControlNew.ascx.cs | 150 +++++++++++++----- src/umbraco.businesslogic/UmbracoSettings.cs | 12 ++ 8 files changed, 232 insertions(+), 65 deletions(-) create mode 100644 src/Umbraco.Core/IconPickerBehaviour.cs diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings.cs b/src/Umbraco.Core/Configuration/UmbracoSettings.cs index 784ebfa686..3feb6ef034 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings.cs @@ -1251,6 +1251,41 @@ namespace Umbraco.Core.Configuration } } + private static IconPickerBehaviour? _iconPickerBehaviour; + + /// + /// This configuration setting defines how to show icons in the document type editor. + /// - ShowDuplicates - Show duplicates in files and sprites. (default and current Umbraco 'normal' behaviour) + /// - HideSpriteDuplicates - Show files on disk and hide duplicates from the sprite + /// - HideFileDuplicates - Show files in the sprite and hide duplicates on disk + /// + /// MacroErrorBehaviour enum defining how to show icons in the document type editor. + public static IconPickerBehaviour IconPickerBehaviour + { + get + { + if (_iconPickerBehaviour == null) + { + try + { + var behaviour = IconPickerBehaviour.ShowDuplicates; + var value = GetKey("/settings/content/DocumentTypeIconList"); + if (value != null) + { + Enum.TryParse(value, true, out behaviour); + } + _iconPickerBehaviour = behaviour; + } + catch (Exception ex) + { + LogHelper.Error("Could not load /settings/content/DocumentTypeIconList from umbracosettings.config", ex); + _iconPickerBehaviour = IconPickerBehaviour.ShowDuplicates; + } + } + return _iconPickerBehaviour.Value; + } + } + /// /// Configuration regarding webservices /// diff --git a/src/Umbraco.Core/IconPickerBehaviour.cs b/src/Umbraco.Core/IconPickerBehaviour.cs new file mode 100644 index 0000000000..d442bbe95d --- /dev/null +++ b/src/Umbraco.Core/IconPickerBehaviour.cs @@ -0,0 +1,24 @@ +namespace Umbraco.Core +{ + public enum IconPickerBehaviour + { + /// + /// Default umbraco behavior - show duplicates in files and sprites + /// + ShowDuplicates, + + /// + /// If a file exists on disk with the same name as one in the sprite + /// then the file on disk overrules the one in the sprite, the + /// sprite icon will not be shown + /// + HideSpriteDuplicates, + + /// + /// If a file exists on disk with the same name as one in the sprite + /// then the file in the sprite overrules the one on disk, the file + /// on disk will be shown + /// + HideFileDuplicates + } +} diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 981b4cb41d..4b4efece82 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -112,6 +112,7 @@ + diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config index bdb473c0b0..733ef87d0f 100644 --- a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config +++ b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config @@ -86,7 +86,7 @@ false - + inline + + + ShowDuplicates @@ -143,7 +157,7 @@ true - + WebForms diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.config b/src/Umbraco.Web.UI/config/umbracoSettings.config index c8872d1c19..17d7a33b5e 100644 --- a/src/Umbraco.Web.UI/config/umbracoSettings.config +++ b/src/Umbraco.Web.UI/config/umbracoSettings.config @@ -87,7 +87,21 @@ - throw - Throw an exception which can be caught by the global error handler defined in Application_OnError. If no such error handler is defined then you'll see the Yellow Screen Of Death (YSOD) error page. Note the error can also be handled by the umbraco.macro.Error event, where you can log/alarm with your own code and change the behaviour per event. --> - inline + inline + + + HideFileDuplicates diff --git a/src/Umbraco.Web.UI/umbraco_client/ui/jquery.dd.js b/src/Umbraco.Web.UI/umbraco_client/ui/jquery.dd.js index decbf15e43..01e5f6112f 100644 --- a/src/Umbraco.Web.UI/umbraco_client/ui/jquery.dd.js +++ b/src/Umbraco.Web.UI/umbraco_client/ui/jquery.dd.js @@ -97,24 +97,23 @@ var t = ""; var clsName = ""; var pH = ""; //addition html - if (options.useSprite != false) { - clsName = ' ' + options.useSprite + ' ' + currentOptOption.className; - } else { - arrow = $(currentOptOption).prop("title"); - var reg = new RegExp(/^\{.*\}$/); - var isJson = reg.test(arrow); - if (options.jsonTitle == true && isJson == true) { - if (arrow.length != 0) { - var obj = eval("[" + arrow + "]"); - img = (typeof obj[0].image == "undefined") ? "" : obj[0].image; - t = (typeof obj[0].title == "undefined") ? "" : obj[0].title; - pH = (typeof obj[0].postHTML == "undefined") ? "" : obj[0].postHTML; - arrow = (img.length == 0) ? "" : ' '; - }; - } else { - arrow = (arrow.length == 0) ? "" : ' '; + + clsName = ' ' + options.useSprite + ' ' + currentOptOption.className; + arrow = $(currentOptOption).prop("title"); + var reg = new RegExp(/^\{.*\}$/); + var isJson = reg.test(arrow); + if (options.jsonTitle == true && isJson == true) { + if (arrow.length != 0) { + var obj = eval("[" + arrow + "]"); + img = (typeof obj[0].image == "undefined") ? "" : obj[0].image; + t = (typeof obj[0].title == "undefined") ? "" : obj[0].title; + pH = (typeof obj[0].postHTML == "undefined") ? "" : obj[0].postHTML; + arrow = (img.length == 0) ? "" : ' '; }; + } else { + arrow = (arrow.length == 0) ? "" : ' '; }; + var sText = $(currentOptOption).text(); var sValue = $(currentOptOption).val(); var sEnabledClass = ($(currentOptOption).prop("disabled") == true) ? "disabled" : "enabled"; @@ -325,7 +324,7 @@ }; }); - } + } }); }; $("#" + childid).bind("mouseout", function (event) { setInsideWindow(false); $(document).unbind("keydown", d_onkeydown); actionSettings.keyboardAction = false; actionSettings.currentKey = null; }); @@ -385,7 +384,7 @@ //shift var currentSelected = $(obj).prop("id"); var currentIndex = a_array[currentSelected].index; - for (var i = Math.min(oldIndex, currentIndex); i <= Math.max(oldIndex, currentIndex); i++) { + for (var i = Math.min(oldIndex, currentIndex) ; i <= Math.max(oldIndex, currentIndex) ; i++) { $("#" + getByIndex(i).id).addClass(styles.selected); }; } else { @@ -621,7 +620,7 @@ if (has_handler('change') == true) { //alert(1); var currentSelected = a_array[$("#" + childid + " a.selected").prop("id")]; - if(currentSelected != undefined) { + if (currentSelected != undefined) { var currentSelectedValue = currentSelected.text; if ($.trim(oldSelectedValue) !== $.trim(currentSelectedValue) && oldSelectedValue !== "") { $("#" + elementid).trigger("change"); @@ -786,9 +785,9 @@ }; if ($("#" + childid).css("display") == "none") { var oldSelected = a_array[$("#" + childid + " a.selected").prop("id")]; - if(oldSelected != undefined) + if (oldSelected != undefined) oldSelectedValue = oldSelected.text; - + //keyboard action inputText = ""; oldHeight = $("#" + childid).height(); diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs index ed98b073c7..2182842d77 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -14,7 +14,7 @@ using umbraco.cms.businesslogic.propertytype; using umbraco.cms.businesslogic.web; using umbraco.cms.helpers; using umbraco.controls.GenericProperties; -using umbraco.IO; +using Umbraco.Core.IO; using umbraco.presentation; using umbraco.BasePages; using ContentType = umbraco.cms.businesslogic.ContentType; @@ -41,7 +41,7 @@ namespace umbraco.controls // "Tab" tab protected uicontrols.Pane Pane8; - + // "Structure" tab protected DualSelectbox DualAllowedContentTypes = new DualSelectbox(); @@ -50,7 +50,7 @@ namespace umbraco.controls // "Generic properties" tab public uicontrols.TabPage GenericPropertiesTabPage; - + public GenericPropertyWrapper gp; private DataTable _dataTypeTable; private ArrayList _genericProperties = new ArrayList(); @@ -113,7 +113,7 @@ namespace umbraco.controls var ea = new SaveClickEventArgs("Saved"); ea.IconType = BasePage.speechBubbleIcon.success; - + //NOTE The saving of the 5 properties (Name, Alias, Icon, Description and Thumbnail) are divided //to avoid the multiple cache flushing when each property is set using the legacy ContentType class, //which has been reduced to the else-clause. @@ -129,7 +129,7 @@ namespace umbraco.controls int i = 0; var ids = SaveAllowedChildTypes(); - _contentType.ContentTypeItem.AllowedContentTypes = ids.Select(x => new ContentTypeSort{ Id = new Lazy(() => x), SortOrder = i++ }); + _contentType.ContentTypeItem.AllowedContentTypes = ids.Select(x => new ContentTypeSort { Id = new Lazy(() => x), SortOrder = i++ }); var tabs = SaveTabs(); foreach (var tab in tabs) @@ -140,7 +140,7 @@ namespace umbraco.controls } else { - _contentType.ContentTypeItem.PropertyGroups.Add(new PropertyGroup{ Id = tab.Item1, Name = tab.Item2, SortOrder = tab.Item3 }); + _contentType.ContentTypeItem.PropertyGroups.Add(new PropertyGroup { Id = tab.Item1, Name = tab.Item2, SortOrder = tab.Item3 }); } } @@ -252,7 +252,7 @@ namespace umbraco.controls } #region "Info" Pane - + private void SetupInfoPane() { InfoTabPage = TabView1.NewTabPage("Info"); @@ -261,38 +261,62 @@ namespace umbraco.controls InfoTabPage.Style.Add("text-align", "center"); ImageButton Save = InfoTabPage.Menu.NewImageButton(); - Save.Click += new System.Web.UI.ImageClickEventHandler(save_click); + Save.Click += save_click; Save.ImageUrl = UmbracoPath + "/images/editor/save.gif"; Save.AlternateText = ui.Text("save"); Save.ID = "save"; - var listOfIcons = new List(); - // Get icons - // nh css file update, add support for css sprites - foreach (string iconClass in cms.businesslogic.CMSNode.DefaultIconClasses) - { - ListItem li = new ListItem(helper.SpaceCamelCasing((iconClass.Substring(1, iconClass.Length - 1))).Replace("Spr Tree", "").Trim(), iconClass); - li.Attributes.Add("class", "spriteBackground sprTree " + iconClass.Trim('.')); - li.Attributes.Add("style", "padding-left:20px !important; background-repeat:no-repeat;"); + + var dirInfo = new DirectoryInfo(UmbracoContext.Current.Server.MapPath(SystemDirectories.Umbraco + "/images/umbraco")); + var fileInfo = dirInfo.GetFiles(); - if (!this.Page.IsPostBack && li.Value == _contentType.IconUrl) li.Selected = true; - listOfIcons.Add(li); + var spriteFileNames = new List(); + foreach (var iconClass in cms.businesslogic.CMSNode.DefaultIconClasses) + spriteFileNames.Add(IconClassToIconFileName(iconClass)); + + var diskFileNames = new List(); + foreach (var file in fileInfo) + diskFileNames.Add(FileNameToIconFileName(file)); + + var listOfIcons = new List(); + + foreach (var iconClass in cms.businesslogic.CMSNode.DefaultIconClasses) + { + // .sprNew was never intended to be in the document type editor + if (iconClass.ToLowerInvariant() == ".sprNew".ToLowerInvariant()) + continue; + + if (_contentType.IconUrl == iconClass) + { + AddSpriteListItem(iconClass, listOfIcons); + continue; + } + + if (UmbracoSettings.IconPickerBehaviour == IconPickerBehaviour.HideSpriteDuplicates + && diskFileNames.Contains(IconClassToIconFileName(iconClass))) + continue; + + AddSpriteListItem(iconClass, listOfIcons); } - DirectoryInfo dirInfo = new DirectoryInfo(UmbracoContext.Current.Server.MapPath(SystemDirectories.Umbraco + "/images/umbraco")); - FileInfo[] fileInfo = dirInfo.GetFiles(); - for (int i = 0; i < fileInfo.Length; i++) + foreach (var file in fileInfo) { // NH: don't show the sprite file - if (fileInfo[i].Name != "sprites.png" && fileInfo[i].Name != "sprites_ie6.gif") - { - ListItem li = new ListItem(fileInfo[i].Name, fileInfo[i].Name); - li.Attributes.Add("title", this.ResolveClientUrl(SystemDirectories.Umbraco + "/images/umbraco/" + fileInfo[i].Name)); + if (file.Name.ToLowerInvariant() == "sprites.png".ToLowerInvariant() || file.Name.ToLowerInvariant() == "sprites_ie6.gif".ToLowerInvariant()) + continue; - if (li.Value == _contentType.IconUrl) - li.Selected = true; - listOfIcons.Add(li); + var listItemValue = this.ResolveClientUrl(SystemDirectories.Umbraco + "/images/umbraco/" + file.Name); + if (_contentType.IconUrl == listItemValue) + { + AddFileListItem(file.Name, listItemValue, listOfIcons); + continue; } + + if (UmbracoSettings.IconPickerBehaviour == IconPickerBehaviour.HideFileDuplicates + && spriteFileNames.Contains(FileNameToIconFileName(file))) + continue; + + AddFileListItem(file.Name, listItemValue, listOfIcons); } ddlIcons.Items.AddRange(listOfIcons.OrderBy(o => o.Text).ToArray()); @@ -300,11 +324,15 @@ namespace umbraco.controls // Get thumbnails dirInfo = new DirectoryInfo(IOHelper.MapPath(SystemDirectories.Umbraco + "/images/thumbnails")); fileInfo = dirInfo.GetFiles(); - for (int i = 0; i < fileInfo.Length; i++) + + foreach (var file in fileInfo) { - ListItem li = new ListItem(fileInfo[i].Name); - li.Attributes.Add("title", this.ResolveClientUrl(SystemDirectories.Umbraco + "/images/thumbnails/" + fileInfo[i].Name)); - if (!this.Page.IsPostBack && li.Value == _contentType.Thumbnail) li.Selected = true; + var li = new ListItem(file.Name); + li.Attributes.Add("title", this.ResolveClientUrl(SystemDirectories.Umbraco + "/images/thumbnails/" + file.Name)); + + if (this.Page.IsPostBack == false && li.Value == _contentType.Thumbnail) + li.Selected = true; + ddlThumbnails.Items.Add(li); } @@ -320,9 +348,49 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); description.Text = _contentType.GetRawDescription(); } - + + private void AddSpriteListItem(string iconClass, ICollection listOfIcons) + { + var li = new ListItem( + helper.SpaceCamelCasing((iconClass.Substring(1, iconClass.Length - 1))) + .Replace("Spr Tree", "") + .Trim(), iconClass); + + li.Attributes.Add("class", "spriteBackground sprTree " + iconClass.Trim('.')); + li.Attributes.Add("style", "padding-left:24px !important; background-repeat:no-repeat; width:auto; height:auto;"); + + AddListItem(listOfIcons, li); + } + + private void AddFileListItem(string fileName, string listItemValue, ICollection listOfIcons) + { + var li = new ListItem(fileName, fileName); + + li.Attributes.Add("title", listItemValue); + + AddListItem(listOfIcons, li); + } + + private void AddListItem(ICollection listOfIcons, ListItem li) + { + if (this.Page.IsPostBack == false && li.Value == _contentType.IconUrl) + li.Selected = true; + + listOfIcons.Add(li); + } + + private static string IconClassToIconFileName(string iconClass) + { + return iconClass.Substring(1, iconClass.Length - 1).ToLowerInvariant().Replace("sprTree".ToLowerInvariant(), ""); + } + + private static string FileNameToIconFileName(FileInfo file) + { + return file.Name.Substring(0, file.Name.LastIndexOf(".", StringComparison.Ordinal)).ToLowerInvariant(); + } + #endregion - + #region "Structure" Pane private void SetupStructurePane() @@ -358,7 +426,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); } DualAllowedContentTypes.Value = chosenContentTypeIDs; } - + allowAtRoot.Checked = _contentType.AllowAtRoot; } @@ -452,7 +520,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); foreach (cms.businesslogic.propertytype.PropertyType pt in propertyTypes) { //If the PropertyType doesn't belong on this ContentType skip it and continue to the next one - if(pt.ContentTypeId != _contentType.Id) continue; + if (pt.ContentTypeId != _contentType.Id) continue; var gpw = new GenericPropertyWrapper(); gpw.ID = "gpw_" + pt.Id; @@ -635,9 +703,9 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); //Loop through the _genericProperties ArrayList and update all existing PropertyTypes foreach (GenericPropertyWrapper gpw in _genericProperties) { - if(gpw.PropertyType == null) continue; + if (gpw.PropertyType == null) continue; - if(contentTypeItem.PropertyTypes == null || contentTypeItem.PropertyTypes.Any(x => x.Alias == gpw.PropertyType.Alias) == false) continue; + if (contentTypeItem.PropertyTypes == null || contentTypeItem.PropertyTypes.Any(x => x.Alias == gpw.PropertyType.Alias) == false) continue; var propertyType = contentTypeItem.PropertyTypes.First(x => x.Alias == gpw.PropertyType.Alias); if (propertyType == null) continue; @@ -786,7 +854,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); { PropertyTypes.Controls.Add(new LiteralControl("
No properties defined on this tab. Click on the \"add a new property\" link at the top to create a new property.
")); } - + private bool DoesPropertyTypeAliasExist(GenericProperty gpData) { bool hasAlias = _contentType.getPropertyType(Casing.SafeAliasWithForcingCheck(gpData.Alias.Trim())) != null; @@ -855,7 +923,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); LoadContentType(_contentType.Id); BindDataGenericProperties(true); } - + #endregion #region "Tab" Pane @@ -863,7 +931,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); private void SetupTabPane() { uicontrols.TabPage tp = TabView1.NewTabPage("Tabs"); - + pnlTab.Style.Add("text-align", "center"); tp.Controls.Add(pnlTab); diff --git a/src/umbraco.businesslogic/UmbracoSettings.cs b/src/umbraco.businesslogic/UmbracoSettings.cs index c7db9fdeb1..1e206dcc16 100644 --- a/src/umbraco.businesslogic/UmbracoSettings.cs +++ b/src/umbraco.businesslogic/UmbracoSettings.cs @@ -562,6 +562,18 @@ namespace umbraco get { return Umbraco.Core.Configuration.UmbracoSettings.MacroErrorBehaviour; } } + /// + /// This configuration setting defines how to show icons in the document type editor. + /// - ShowDuplicates - Show duplicates in files and sprites. (default and current Umbraco 'normal' behaviour) + /// - HideSpriteDuplicates - Show files on disk and hide duplicates from the sprite + /// - HideFileDuplicates - Show files in the sprite and hide duplicates on disk + /// + /// MacroErrorBehaviour enum defining how to show icons in the document type editor. + public static IconPickerBehaviour IconPickerBehaviour + { + get { return Umbraco.Core.Configuration.UmbracoSettings.IconPickerBehaviour; } + } + /// /// Configuration regarding webservices /// From bea50f456234c3711ae4fd0c91cf4f494b84366e Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 1 Apr 2013 11:50:27 -0200 Subject: [PATCH 06/16] Fixes: U4-662 Most icon for document type can't be shown in 4.8.1. --- .../Configuration/UmbracoSettings.cs | 35 +++ src/Umbraco.Core/IconPickerBehaviour.cs | 24 ++ src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../config/umbracoSettings.Release.config | 14 ++ .../config/umbracoSettings.config | 14 ++ .../umbraco_client/ui/jquery.dd.js | 5 +- .../controls/ContentTypeControlNew.ascx.cs | 217 ++++++++++++------ src/umbraco.businesslogic/UmbracoSettings.cs | 12 + 8 files changed, 245 insertions(+), 77 deletions(-) create mode 100644 src/Umbraco.Core/IconPickerBehaviour.cs diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings.cs b/src/Umbraco.Core/Configuration/UmbracoSettings.cs index e3c15b1a10..38ab03e97d 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings.cs @@ -1250,6 +1250,41 @@ namespace Umbraco.Core.Configuration } } + private static IconPickerBehaviour? _iconPickerBehaviour; + + /// + /// This configuration setting defines how to show icons in the document type editor. + /// - ShowDuplicates - Show duplicates in files and sprites. (default and current Umbraco 'normal' behaviour) + /// - HideSpriteDuplicates - Show files on disk and hide duplicates from the sprite + /// - HideFileDuplicates - Show files in the sprite and hide duplicates on disk + /// + /// MacroErrorBehaviour enum defining how to show icons in the document type editor. + public static IconPickerBehaviour IconPickerBehaviour + { + get + { + if (_iconPickerBehaviour == null) + { + try + { + var behaviour = IconPickerBehaviour.ShowDuplicates; + var value = GetKey("/settings/content/DocumentTypeIconList"); + if (value != null) + { + Enum.TryParse(value, true, out behaviour); + } + _iconPickerBehaviour = behaviour; + } + catch (Exception ex) + { + LogHelper.Error("Could not load /settings/content/DocumentTypeIconList from umbracosettings.config", ex); + _iconPickerBehaviour = IconPickerBehaviour.ShowDuplicates; + } + } + return _iconPickerBehaviour.Value; + } + } + /// /// Configuration regarding webservices /// diff --git a/src/Umbraco.Core/IconPickerBehaviour.cs b/src/Umbraco.Core/IconPickerBehaviour.cs new file mode 100644 index 0000000000..d442bbe95d --- /dev/null +++ b/src/Umbraco.Core/IconPickerBehaviour.cs @@ -0,0 +1,24 @@ +namespace Umbraco.Core +{ + public enum IconPickerBehaviour + { + /// + /// Default umbraco behavior - show duplicates in files and sprites + /// + ShowDuplicates, + + /// + /// If a file exists on disk with the same name as one in the sprite + /// then the file on disk overrules the one in the sprite, the + /// sprite icon will not be shown + /// + HideSpriteDuplicates, + + /// + /// If a file exists on disk with the same name as one in the sprite + /// then the file in the sprite overrules the one on disk, the file + /// on disk will be shown + /// + HideFileDuplicates + } +} diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 9d79e46418..3e4320b356 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -71,6 +71,7 @@ + diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config index 669f213dc7..96b2d65cf6 100644 --- a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config +++ b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config @@ -94,6 +94,20 @@ error handler is defined then you'll see the Yellow Screen Of Death (YSOD) error page. Note the error can also be handled by the umbraco.macro.Error event, where you can log/alarm with your own code and change the behaviour per event. --> inline + + + ShowDuplicates
diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.config b/src/Umbraco.Web.UI/config/umbracoSettings.config index c8872d1c19..fd614c87d4 100644 --- a/src/Umbraco.Web.UI/config/umbracoSettings.config +++ b/src/Umbraco.Web.UI/config/umbracoSettings.config @@ -88,6 +88,20 @@ error handler is defined then you'll see the Yellow Screen Of Death (YSOD) error page. Note the error can also be handled by the umbraco.macro.Error event, where you can log/alarm with your own code and change the behaviour per event. --> inline + + + HideFileDuplicates diff --git a/src/Umbraco.Web.UI/umbraco_client/ui/jquery.dd.js b/src/Umbraco.Web.UI/umbraco_client/ui/jquery.dd.js index decbf15e43..dd1837c1a7 100644 --- a/src/Umbraco.Web.UI/umbraco_client/ui/jquery.dd.js +++ b/src/Umbraco.Web.UI/umbraco_client/ui/jquery.dd.js @@ -97,9 +97,8 @@ var t = ""; var clsName = ""; var pH = ""; //addition html - if (options.useSprite != false) { + clsName = ' ' + options.useSprite + ' ' + currentOptOption.className; - } else { arrow = $(currentOptOption).prop("title"); var reg = new RegExp(/^\{.*\}$/); var isJson = reg.test(arrow); @@ -114,7 +113,7 @@ } else { arrow = (arrow.length == 0) ? "" : ' '; }; - }; + var sText = $(currentOptOption).text(); var sValue = $(currentOptOption).val(); var sEnabledClass = ($(currentOptOption).prop("disabled") == true) ? "disabled" : "enabled"; diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs index 123ef70263..9c4d013b15 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -8,10 +8,11 @@ using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using ClientDependency.Core; +using Umbraco.Core; using umbraco.cms.helpers; using umbraco.cms.presentation.Trees; using umbraco.controls.GenericProperties; -using umbraco.IO; +using Umbraco.Core.IO; using umbraco.presentation; using umbraco.cms.businesslogic; using umbraco.BasePages; @@ -33,7 +34,7 @@ namespace umbraco.controls public uicontrols.TabPage InfoTabPage; // General Private members - private cms.businesslogic.ContentType cType; + private cms.businesslogic.ContentType _contentType; private static string UmbracoPath = SystemDirectories.Umbraco; public bool HideStructure { get; set; } @@ -60,7 +61,7 @@ namespace umbraco.controls base.OnInit(e); int docTypeId = getDocTypeId(); - cType = new cms.businesslogic.ContentType(docTypeId); + _contentType = new cms.businesslogic.ContentType(docTypeId); setupInfoPane(); if (!HideStructure) @@ -91,9 +92,9 @@ namespace umbraco.controls // we'll disable this... - if (!Page.IsPostBack && cType.MasterContentType != 0) + if (!Page.IsPostBack && _contentType.MasterContentType != 0) { - string masterName = cms.businesslogic.ContentType.GetContentType(cType.MasterContentType).Text; + string masterName = cms.businesslogic.ContentType.GetContentType(_contentType.MasterContentType).Text; tabsMasterContentTypeName.Text = masterName; propertiesMasterContentTypeName.Text = masterName; PaneTabsInherited.Visible = true; @@ -110,14 +111,14 @@ namespace umbraco.controls // --- // Keep a reference of the original doctype alias and name - var originalDocTypeAlias = cType.Alias; - var originalDocTypeName = cType.Text; + var originalDocTypeAlias = _contentType.Alias; + var originalDocTypeName = _contentType.Text; - cType.Text = txtName.Text; - cType.Alias = txtAlias.Text; - cType.IconUrl = ddlIcons.SelectedValue; - cType.Description = description.Text; - cType.Thumbnail = ddlThumbnails.SelectedValue; + _contentType.Text = txtName.Text; + _contentType.Alias = txtAlias.Text; + _contentType.IconUrl = ddlIcons.SelectedValue; + _contentType.Description = description.Text; + _contentType.Thumbnail = ddlThumbnails.SelectedValue; SaveClickEventArgs ea = new SaveClickEventArgs("Saved"); ea.IconType = umbraco.BasePages.BasePage.speechBubbleIcon.success; @@ -128,12 +129,12 @@ namespace umbraco.controls SaveAllowedChildTypes(); // reload content type (due to caching) - cType = new ContentType(cType.Id); + _contentType = new ContentType(_contentType.Id); // Check if the doctype alias has changed as a result of either the user input or // the alias checking performed upon saving - var docTypeAliasChanged = (string.Compare(originalDocTypeAlias, cType.Alias, true) != 0); - var docTypeNameChanged = (string.Compare(originalDocTypeName, cType.Text, true) != 0); + var docTypeAliasChanged = (string.Compare(originalDocTypeAlias, _contentType.Alias, true) != 0); + var docTypeNameChanged = (string.Compare(originalDocTypeName, _contentType.Text, true) != 0); // Only if the doctype alias changed, cause a regeneration of the xml cache file since // the xml element names will need to be updated to reflect the new alias @@ -143,7 +144,7 @@ namespace umbraco.controls bindDataGenericProperties(true); // we need to re-bind the alias as the SafeAlias method can have changed it - txtAlias.Text = cType.Alias; + txtAlias.Text = _contentType.Alias; RaiseBubbleEvent(new object(), ea); @@ -164,7 +165,7 @@ namespace umbraco.controls { var clientTools = new ClientTools(this.Page); clientTools - .SyncTree(cType.Path, true); + .SyncTree(_contentType.Path, true); } #region "Info" Pane @@ -178,38 +179,62 @@ namespace umbraco.controls InfoTabPage.Style.Add("text-align", "center"); ImageButton Save = InfoTabPage.Menu.NewImageButton(); - Save.Click += new System.Web.UI.ImageClickEventHandler(save_click); + Save.Click += save_click; Save.ImageUrl = UmbracoPath + "/images/editor/save.gif"; Save.AlternateText = ui.Text("save"); Save.ID = "save"; - var listOfIcons = new List(); - // Get icons - // nh css file update, add support for css sprites - foreach (string iconClass in cms.businesslogic.CMSNode.DefaultIconClasses) - { - ListItem li = new ListItem(helper.SpaceCamelCasing((iconClass.Substring(1, iconClass.Length - 1))).Replace("Spr Tree", "").Trim(), iconClass); - li.Attributes.Add("class", "spriteBackground sprTree " + iconClass.Trim('.')); - li.Attributes.Add("style", "padding-left:20px !important; background-repeat:no-repeat;"); - if (!this.Page.IsPostBack && li.Value == cType.IconUrl) li.Selected = true; - listOfIcons.Add(li); + var dirInfo = new DirectoryInfo(UmbracoContext.Current.Server.MapPath(SystemDirectories.Umbraco + "/images/umbraco")); + var fileInfo = dirInfo.GetFiles(); + + var spriteFileNames = new List(); + foreach (var iconClass in cms.businesslogic.CMSNode.DefaultIconClasses) + spriteFileNames.Add(IconClassToIconFileName(iconClass)); + + var diskFileNames = new List(); + foreach (var file in fileInfo) + diskFileNames.Add(FileNameToIconFileName(file)); + + var listOfIcons = new List(); + + foreach (var iconClass in cms.businesslogic.CMSNode.DefaultIconClasses) + { + // .sprNew was never intended to be in the document type editor + if (iconClass.ToLowerInvariant() == ".sprNew".ToLowerInvariant()) + continue; + + if (_contentType.IconUrl == iconClass) + { + AddSpriteListItem(iconClass, listOfIcons); + continue; + } + + if (UmbracoSettings.IconPickerBehaviour == IconPickerBehaviour.HideSpriteDuplicates + && diskFileNames.Contains(IconClassToIconFileName(iconClass))) + continue; + + AddSpriteListItem(iconClass, listOfIcons); } - DirectoryInfo dirInfo = new DirectoryInfo(UmbracoContext.Current.Server.MapPath(SystemDirectories.Umbraco + "/images/umbraco")); - FileInfo[] fileInfo = dirInfo.GetFiles(); - for (int i = 0; i < fileInfo.Length; i++) + foreach (var file in fileInfo) { // NH: don't show the sprite file - if (fileInfo[i].Name != "sprites.png" && fileInfo[i].Name != "sprites_ie6.gif") - { - ListItem li = new ListItem(fileInfo[i].Name, fileInfo[i].Name); - li.Attributes.Add("title", this.ResolveClientUrl(SystemDirectories.Umbraco + "/images/umbraco/" + fileInfo[i].Name)); + if (file.Name.ToLowerInvariant() == "sprites.png".ToLowerInvariant() || file.Name.ToLowerInvariant() == "sprites_ie6.gif".ToLowerInvariant()) + continue; - if (li.Value == cType.IconUrl) - li.Selected = true; - listOfIcons.Add(li); + var listItemValue = this.ResolveClientUrl(SystemDirectories.Umbraco + "/images/umbraco/" + file.Name); + if (_contentType.IconUrl == listItemValue) + { + AddFileListItem(file.Name, listItemValue, listOfIcons); + continue; } + + if (UmbracoSettings.IconPickerBehaviour == IconPickerBehaviour.HideFileDuplicates + && spriteFileNames.Contains(FileNameToIconFileName(file))) + continue; + + AddFileListItem(file.Name, listItemValue, listOfIcons); } ddlIcons.Items.AddRange(listOfIcons.OrderBy(o => o.Text).ToArray()); @@ -217,11 +242,15 @@ namespace umbraco.controls // Get thumbnails dirInfo = new DirectoryInfo(IOHelper.MapPath(SystemDirectories.Umbraco + "/images/thumbnails")); fileInfo = dirInfo.GetFiles(); - for (int i = 0; i < fileInfo.Length; i++) + + foreach (var file in fileInfo) { - ListItem li = new ListItem(fileInfo[i].Name); - li.Attributes.Add("title", this.ResolveClientUrl(SystemDirectories.Umbraco + "/images/thumbnails/" + fileInfo[i].Name)); - if (!this.Page.IsPostBack && li.Value == cType.Thumbnail) li.Selected = true; + var li = new ListItem(file.Name); + li.Attributes.Add("title", this.ResolveClientUrl(SystemDirectories.Umbraco + "/images/thumbnails/" + file.Name)); + + if (this.Page.IsPostBack == false && li.Value == _contentType.Thumbnail) + li.Selected = true; + ddlThumbnails.Items.Add(li); } @@ -232,11 +261,51 @@ function refreshDropDowns() {{ }} jQuery(document).ready(function() {{ refreshDropDowns(); }}); ", ddlIcons.ClientID, ddlIcons.ClientID, ddlIcons.ClientID, ddlThumbnails.ClientID, 500), true); - txtName.Text = cType.GetRawText(); - txtAlias.Text = cType.Alias; - description.Text = cType.GetRawDescription(); + txtName.Text = _contentType.GetRawText(); + txtAlias.Text = _contentType.Alias; + description.Text = _contentType.GetRawDescription(); } + + private void AddSpriteListItem(string iconClass, ICollection listOfIcons) + { + var li = new ListItem( + helper.SpaceCamelCasing((iconClass.Substring(1, iconClass.Length - 1))) + .Replace("Spr Tree", "") + .Trim(), iconClass); + + li.Attributes.Add("class", "spriteBackground sprTree " + iconClass.Trim('.')); + li.Attributes.Add("style", "padding-left:24px !important; background-repeat:no-repeat; width:auto; height:auto;"); + + AddListItem(listOfIcons, li); + } + + private void AddFileListItem(string fileName, string listItemValue, ICollection listOfIcons) + { + var li = new ListItem(fileName, fileName); + + li.Attributes.Add("title", listItemValue); + + AddListItem(listOfIcons, li); + } + + private void AddListItem(ICollection listOfIcons, ListItem li) + { + if (this.Page.IsPostBack == false && li.Value == _contentType.IconUrl) + li.Selected = true; + + listOfIcons.Add(li); + } + + private static string IconClassToIconFileName(string iconClass) + { + return iconClass.Substring(1, iconClass.Length - 1).ToLowerInvariant().Replace("sprTree".ToLowerInvariant(), ""); + } + + private static string FileNameToIconFileName(FileInfo file) + { + return file.Name.Substring(0, file.Name.LastIndexOf(".", StringComparison.Ordinal)).ToLowerInvariant(); + } #endregion @@ -253,11 +322,11 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); Save.Click += new System.Web.UI.ImageClickEventHandler(save_click); Save.ImageUrl = UmbracoPath + "/images/editor/save.gif"; - int[] allowedIds = cType.AllowedChildContentTypeIDs; + int[] allowedIds = _contentType.AllowedChildContentTypeIDs; if (!Page.IsPostBack) { string chosenContentTypeIDs = ""; - ContentType[] contentTypes = cType.GetAll(); + ContentType[] contentTypes = _contentType.GetAll(); foreach (cms.businesslogic.ContentType ct in contentTypes.OrderBy(x => x.Text)) { ListItem li = new ListItem(ct.Text, ct.Id.ToString()); @@ -286,7 +355,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); } int[] ids = new int[tmp.Count]; for (int i = 0; i < tmp.Count; i++) ids[i] = (int)tmp[i]; - cType.AllowedChildContentTypeIDs = ids; + _contentType.AllowedChildContentTypeIDs = ids; } #endregion @@ -319,7 +388,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); } private void bindDataGenericProperties(bool Refresh) { - cms.businesslogic.ContentType.TabI[] tabs = cType.getVirtualTabs; + cms.businesslogic.ContentType.TabI[] tabs = _contentType.getVirtualTabs; cms.businesslogic.datatype.DataTypeDefinition[] dtds = cms.businesslogic.datatype.DataTypeDefinition.GetAll(); PropertyTypes.Controls.Clear(); @@ -363,11 +432,11 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); foreach (cms.businesslogic.ContentType.TabI t in tabs) { bool hasProperties = false; - string tabCaption = t.ContentType == cType.Id ? t.GetRawCaption() : t.GetRawCaption() + " (inherited from " + new ContentType(t.ContentType).Text + ")"; + string tabCaption = t.ContentType == _contentType.Id ? t.GetRawCaption() : t.GetRawCaption() + " (inherited from " + new ContentType(t.ContentType).Text + ")"; PropertyTypes.Controls.Add(new LiteralControl("

Tab: " + tabCaption + "

")); // zb-00036 #29889 : fix property types getter - var propertyTypes = t.GetPropertyTypes(cType.Id, false); + var propertyTypes = t.GetPropertyTypes(_contentType.Id, false); if (propertyTypes.Length > 0) { @@ -452,12 +521,12 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); propertiesPH.Controls.Add(new LiteralControl("
    ")); - foreach (cms.businesslogic.propertytype.PropertyType pt in cType.PropertyTypes) + foreach (cms.businesslogic.propertytype.PropertyType pt in _contentType.PropertyTypes) { //This use to be: //if (pt.ContentTypeId == cType.Id && !inTab.ContainsKey(pt.Id.ToString()) //But seriously, if it's not on a tab the tabId is 0, it's a lot easier to read IMO - if (pt.ContentTypeId == cType.Id && pt.TabId == 0) + if (pt.ContentTypeId == _contentType.Id && pt.TabId == 0) { GenericProperties.GenericPropertyWrapper gpw = new umbraco.controls.GenericProperties.GenericPropertyWrapper(); @@ -519,7 +588,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); { GenericProperties.GenericPropertyWrapper gpw = (GenericProperties.GenericPropertyWrapper)sender; gpw.GenricPropertyControl.PropertyType.delete(); - cType = ContentType.GetContentType(cType.Id); + _contentType = ContentType.GetContentType(_contentType.Id); this.bindDataGenericProperties(true); } @@ -528,7 +597,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); { // Data bind create new - gp.GenricPropertyControl.Tabs = cType.getVirtualTabs; + gp.GenricPropertyControl.Tabs = _contentType.getVirtualTabs; gp.GenricPropertyControl.DataTypeDefinitions = cms.businesslogic.datatype.DataTypeDefinition.GetAll(); DataSet ds = new DataSet(); @@ -551,7 +620,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); dtT.Columns.Add("genericProperties"); Hashtable inTab = new Hashtable(); - foreach (cms.businesslogic.ContentType.TabI tb in cType.getVirtualTabs.ToList()) + foreach (cms.businesslogic.ContentType.TabI tb in _contentType.getVirtualTabs.ToList()) { DataRow dr = dtT.NewRow(); dr["TabName"] = tb.GetRawCaption(); @@ -559,7 +628,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); dtT.Rows.Add(dr); // zb-00036 #29889 : fix property types getter - foreach (cms.businesslogic.propertytype.PropertyType pt in tb.GetPropertyTypes(cType.Id)) + foreach (cms.businesslogic.propertytype.PropertyType pt in tb.GetPropertyTypes(_contentType.Id)) { DataRow dr1 = dtP.NewRow(); dr1["alias"] = pt.Alias; @@ -578,7 +647,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); dr2["tabid"] = 0; dtT.Rows.Add(dr2); - foreach (cms.businesslogic.propertytype.PropertyType pt in cType.PropertyTypes) + foreach (cms.businesslogic.propertytype.PropertyType pt in _contentType.PropertyTypes) { if (!inTab.ContainsKey(pt.Id.ToString())) { @@ -608,14 +677,14 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); if (doesPropertyTypeAliasExist(gpData)) { string[] info = { gpData.Name, gpData.Type.ToString() }; - cms.businesslogic.propertytype.PropertyType pt = cType.AddPropertyType(cms.businesslogic.datatype.DataTypeDefinition.GetDataTypeDefinition(gpData.Type), Casing.SafeAliasWithForcingCheck(gpData.Alias.Trim()), gpData.Name); + cms.businesslogic.propertytype.PropertyType pt = _contentType.AddPropertyType(cms.businesslogic.datatype.DataTypeDefinition.GetDataTypeDefinition(gpData.Type), Casing.SafeAliasWithForcingCheck(gpData.Alias.Trim()), gpData.Name); pt.Mandatory = gpData.Mandatory; pt.ValidationRegExp = gpData.Validation; pt.Description = gpData.Description; if (gpData.Tab != 0) { - cType.SetTabOnPropertyType(pt, gpData.Tab); + _contentType.SetTabOnPropertyType(pt, gpData.Tab); } gpData.Clear(); @@ -638,9 +707,9 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); pt.Mandatory = gpw.GenricPropertyControl.Mandatory; pt.DataTypeDefinition = cms.businesslogic.datatype.DataTypeDefinition.GetDataTypeDefinition(gpw.GenricPropertyControl.Type); if (gpw.GenricPropertyControl.Tab == 0) - cType.removePropertyTypeFromTab(pt); + _contentType.removePropertyTypeFromTab(pt); else - cType.SetTabOnPropertyType(pt, gpw.GenricPropertyControl.Tab); + _contentType.SetTabOnPropertyType(pt, gpw.GenricPropertyControl.Tab); pt.Save(); } @@ -669,8 +738,8 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); private bool doesPropertyTypeAliasExist(GenericProperty gpData) { - bool hasAlias = cType.getPropertyType(Casing.SafeAliasWithForcingCheck(gpData.Alias.Trim())) != null; - ContentType ct = cType; + bool hasAlias = _contentType.getPropertyType(Casing.SafeAliasWithForcingCheck(gpData.Alias.Trim())) != null; + ContentType ct = _contentType; while (ct.MasterContentType > 0) { ct = new ContentType(ct.MasterContentType); @@ -687,13 +756,13 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); { if (e.CommandName == "Delete") { - cType.DeleteVirtualTab(int.Parse(e.CommandArgument.ToString())); + _contentType.DeleteVirtualTab(int.Parse(e.CommandArgument.ToString())); } if (e.CommandName == "MoveDown") { int TabId = int.Parse(e.CommandArgument.ToString()); - foreach (cms.businesslogic.ContentType.TabI t in cType.getVirtualTabs.ToList()) + foreach (cms.businesslogic.ContentType.TabI t in _contentType.getVirtualTabs.ToList()) { if (t.Id == TabId) { @@ -705,7 +774,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); if (e.CommandName == "MoveUp") { int TabId = int.Parse(e.CommandArgument.ToString()); - foreach (cms.businesslogic.ContentType.TabI t in cType.getVirtualTabs.ToList()) + foreach (cms.businesslogic.ContentType.TabI t in _contentType.getVirtualTabs.ToList()) { if (t.Id == TabId) { @@ -765,9 +834,9 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); dt.Columns.Add("name"); dt.Columns.Add("id"); dt.Columns.Add("order"); - foreach (cms.businesslogic.ContentType.TabI tb in cType.getVirtualTabs.ToList()) + foreach (cms.businesslogic.ContentType.TabI tb in _contentType.getVirtualTabs.ToList()) { - if (tb.ContentType == cType.Id) + if (tb.ContentType == _contentType.Id) { DataRow dr = dt.NewRow(); dr["name"] = tb.GetRawCaption(); @@ -847,8 +916,8 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); { if (txtNewTab.Text.Trim() != "") { - cType.AddVirtualTab(txtNewTab.Text); - cType = new ContentType(cType.Id); + _contentType.AddVirtualTab(txtNewTab.Text); + _contentType = new ContentType(_contentType.Id); SaveClickEventArgs ea = new SaveClickEventArgs(ui.Text("contentTypeTabCreated")); ea.IconType = umbraco.BasePages.BasePage.speechBubbleIcon.success; @@ -870,7 +939,7 @@ Umbraco.Controls.TabView.onActiveTabChange(function(tabviewid, tabid, tabs) { { if (e.CommandName == "Delete") { - cType.DeleteVirtualTab(int.Parse(e.Item.Cells[0].Text)); + _contentType.DeleteVirtualTab(int.Parse(e.Item.Cells[0].Text)); SaveClickEventArgs ea = new SaveClickEventArgs(ui.Text("contentTypeTabDeleted")); ea.IconType = umbraco.BasePages.BasePage.speechBubbleIcon.success; @@ -894,10 +963,10 @@ Umbraco.Controls.TabView.onActiveTabChange(function(tabviewid, tabid, tabs) { { tabid = int.Parse(dgi.Cells[0].Text); tabName = ((TextBox)dgi.FindControl("txtTab")).Text.Replace("'", "''"); - cType.SetTabName(tabid, tabName); + _contentType.SetTabName(tabid, tabName); if (Int32.TryParse(((TextBox)dgi.FindControl("txtSortOrder")).Text, out tabSortOrder)) { - cType.SetTabSortOrder(tabid, tabSortOrder); + _contentType.SetTabSortOrder(tabid, tabSortOrder); } } } diff --git a/src/umbraco.businesslogic/UmbracoSettings.cs b/src/umbraco.businesslogic/UmbracoSettings.cs index c7db9fdeb1..1e206dcc16 100644 --- a/src/umbraco.businesslogic/UmbracoSettings.cs +++ b/src/umbraco.businesslogic/UmbracoSettings.cs @@ -562,6 +562,18 @@ namespace umbraco get { return Umbraco.Core.Configuration.UmbracoSettings.MacroErrorBehaviour; } } + /// + /// This configuration setting defines how to show icons in the document type editor. + /// - ShowDuplicates - Show duplicates in files and sprites. (default and current Umbraco 'normal' behaviour) + /// - HideSpriteDuplicates - Show files on disk and hide duplicates from the sprite + /// - HideFileDuplicates - Show files in the sprite and hide duplicates on disk + /// + /// MacroErrorBehaviour enum defining how to show icons in the document type editor. + public static IconPickerBehaviour IconPickerBehaviour + { + get { return Umbraco.Core.Configuration.UmbracoSettings.IconPickerBehaviour; } + } + /// /// Configuration regarding webservices /// From 71aa248a4ee03694a06fb8c6a1df629fad2fc85d Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 1 Apr 2013 14:27:20 -0200 Subject: [PATCH 07/16] Fixes U4-535 Stylesheet content gets deleted if you change case --- .../umbraco/webservices/codeEditorSave.asmx.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/codeEditorSave.asmx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/codeEditorSave.asmx.cs index 722abb3d18..08efdbaa48 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/codeEditorSave.asmx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/codeEditorSave.asmx.cs @@ -60,7 +60,7 @@ namespace umbraco.presentation.webservices //deletes the old css file if the name was changed... - if (fileName != oldName) + if (fileName.ToLowerInvariant() != oldName.ToLowerInvariant()) { string p = IOHelper.MapPath(SystemDirectories.Css + "/" + oldName + ".css"); if (System.IO.File.Exists(p)) From 19c2841576082f36f539d0029be15c5354522e89 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 1 Apr 2013 14:27:20 -0200 Subject: [PATCH 08/16] Fixes U4-535 Stylesheet content gets deleted if you change case --- .../umbraco/webservices/codeEditorSave.asmx.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/codeEditorSave.asmx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/codeEditorSave.asmx.cs index 9d34946b21..fc8961bef1 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/codeEditorSave.asmx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/codeEditorSave.asmx.cs @@ -59,7 +59,7 @@ namespace umbraco.presentation.webservices //deletes the old css file if the name was changed... - if (fileName != oldName) + if (fileName.ToLowerInvariant() != oldName.ToLowerInvariant()) { string p = IOHelper.MapPath(SystemDirectories.Css + "/" + oldName + ".css"); if (System.IO.File.Exists(p)) From 6768bb4793ac82d73675fb008fa8bd5fe184bed9 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Mon, 1 Apr 2013 23:12:17 +0600 Subject: [PATCH 09/16] Fixes: #U4-1874 - merges in thread-safe fixes for static object caching from 6.1 and cleans up a bunch of the code in ContentType.cs. Back ports fixes for Languages.cs from 6.1 and cleans up code. --- src/umbraco.cms/businesslogic/ContentType.cs | 607 +++++++----------- .../businesslogic/language/Language.cs | 203 +++--- 2 files changed, 336 insertions(+), 474 deletions(-) diff --git a/src/umbraco.cms/businesslogic/ContentType.cs b/src/umbraco.cms/businesslogic/ContentType.cs index 073324fa96..9634047464 100644 --- a/src/umbraco.cms/businesslogic/ContentType.cs +++ b/src/umbraco.cms/businesslogic/ContentType.cs @@ -4,13 +4,13 @@ using System.Collections.Generic; using System.Threading; using System.Runtime.CompilerServices; using System.Linq; -using umbraco.cms.businesslogic.cache; -using umbraco.cms.businesslogic.datatype; -using umbraco.cms.businesslogic.language; -using umbraco.cms.businesslogic.propertytype; +using Umbraco.Core; +using Umbraco.Core.Logging; using umbraco.cms.businesslogic.web; using umbraco.DataLayer; -using umbraco.BusinessLogic; +using DataTypeDefinition = umbraco.cms.businesslogic.datatype.DataTypeDefinition; +using Language = umbraco.cms.businesslogic.language.Language; +using PropertyType = umbraco.cms.businesslogic.propertytype.PropertyType; namespace umbraco.cms.businesslogic { @@ -44,24 +44,6 @@ namespace umbraco.cms.businesslogic public ContentType(Guid id, bool noSetup) : base(id, noSetup) { } - ///// - ///// Initializes a new instance of the class. - ///// - ///// The id. - ///// if set to true [use optimized mode] which loads in the data from the - ///// database in an optimized manner (less queries) - ///// - //public ContentType(bool optimizedMode, int id) - // : base(id, optimizedMode) - //{ - // this._optimizedMode = optimizedMode; - - // if (optimizedMode) - // { - - // } - //} - /// /// Creates a new content type object manually. /// @@ -82,7 +64,7 @@ namespace umbraco.cms.businesslogic _iconurl = icon; _thumbnail = thumbnail; if (masterContentType.HasValue) - m_masterContentType = masterContentType.Value; + _masterContentType = masterContentType.Value; } #endregion @@ -95,8 +77,6 @@ namespace umbraco.cms.businesslogic FROM umbracoNode INNER JOIN cmsContentType ON umbracoNode.id = cmsContentType.nodeId WHERE nodeObjectType = @nodeObjectType"; - private static readonly object m_Locker = new object(); - #endregion #region Static Methods @@ -105,8 +85,7 @@ namespace umbraco.cms.businesslogic /// Used for cache so we don't have to lookup column names all the time, this is actually only used for the ChildrenAsTable methods ///
private static readonly ConcurrentDictionary> AliasToNames = new ConcurrentDictionary>(); - - private static Dictionary, Guid> _propertyTypeCache = new Dictionary, Guid>(); + private static readonly ConcurrentDictionary, Guid> PropertyTypeCache = new ConcurrentDictionary, Guid>(); /// /// Returns a content type's columns alias -> name mapping @@ -118,121 +97,108 @@ namespace umbraco.cms.businesslogic /// internal static IDictionary GetAliasesAndNames(string contentTypeAlias) { - IDictionary cached; - if (AliasToNames.TryGetValue(contentTypeAlias, out cached)) - { - return cached; - } - - var ct = ContentType.GetByAlias(contentTypeAlias); - var userFields = ct.PropertyTypes.ToDictionary(x => x.Alias, x => x.Name); - AliasToNames.TryAdd(contentTypeAlias, userFields); - return userFields; + return AliasToNames.GetOrAdd(contentTypeAlias, s => + { + var ct = GetByAlias(contentTypeAlias); + var userFields = ct.PropertyTypes.ToDictionary(x => x.Alias, x => x.Name); + return userFields; + }); } - - public static void RemoveFromDataTypeCache(string contentTypeAlias) + + /// + /// Removes the static object cache + /// + /// + public static void RemoveFromDataTypeCache(string contentTypeAlias) { - lock (_propertyTypeCache) + var toDelete = PropertyTypeCache.Keys.Where(key => string.Equals(key.Item1, contentTypeAlias)).ToList(); + foreach (var key in toDelete) { - List> toDelete = new List>(); - foreach (Tuple key in _propertyTypeCache.Keys) - { - if (string.Equals(key.first, contentTypeAlias)) - { - toDelete.Add(key); - } - } - foreach (Tuple key in toDelete) - { - if(_propertyTypeCache != null) - _propertyTypeCache.Remove(key); - } + Guid id; + PropertyTypeCache.TryRemove(key, out id); } - //don't put lock around this as it is ConcurrentDictionary. - AliasToNames.Clear(); + AliasToNames.Clear(); } + + /// + /// Removes the static object cache + /// + internal static void RemoveAllDataTypeCache() + { + AliasToNames.Clear(); + PropertyTypeCache.Clear(); + } + public static Guid GetDataType(string contentTypeAlias, string propertyTypeAlias) { - Tuple key = new Tuple() - { - first = contentTypeAlias, - second = propertyTypeAlias - }; - //The property type is not on IProperty (it's not stored in NodeFactory) - //first check the cache - if (_propertyTypeCache != null && _propertyTypeCache.ContainsKey(key)) - { - return _propertyTypeCache[key]; - } + var key = new System.Tuple(contentTypeAlias, propertyTypeAlias); - //Instead of going via API, run this query to find the control type - //by-passes a lot of queries just to determine if this is a true/false data type - - //This SQL returns a larger recordset than intended - //causing controlId to sometimes be null instead of correct - //because all properties for the type are returned - //side effect of changing inner join to left join when adding masterContentType - //string sql = "select " + - // "cmsDataType.controlId, masterContentType.alias as masterAlias " + - // "from " + - // "cmsContentType " + - // "inner join cmsPropertyType on (cmsContentType.nodeId = cmsPropertyType.contentTypeId) " + - // "left join cmsDataType on (cmsPropertyType.dataTypeId = cmsDataType.nodeId) and cmsPropertyType.Alias = @propertyAlias " + - // "left join cmsContentType masterContentType on masterContentType.nodeid = cmsContentType.masterContentType " + - // "where cmsContentType.alias = @contentTypeAlias"; - - //this SQL correctly returns a single row when the property exists, but still returns masterAlias if it doesn't - string sql = "select cmsDataType.controlId, masterContentType.alias as masterAlias " + - "from " + - "cmsContentType " + - "left join cmsPropertyType on (cmsContentType.nodeId = cmsPropertyType.contentTypeId and cmsPropertyType.Alias = @propertyAlias) " + - "left join cmsDataType on (cmsPropertyType.dataTypeId = cmsDataType.nodeId) " + - "left join cmsContentType masterContentType on masterContentType.nodeid = cmsContentType.masterContentType " + - "where " + - "cmsContentType.alias = @contentTypeAlias"; - - //Ensure that getdatatype doesn't throw an exception - //http://our.umbraco.org/forum/developers/razor/18085-Access-custom-node-properties-with-Razor - - //grab the controlid or test for parent - Guid controlId = Guid.Empty; - IRecordsReader reader = null; + //NOTE: We only have a try/catch here for legacy reasons, I don't see any reason to have it + // but it was here before so we'll need to keep it for this legacy version. + // If an error occurs, we return an empty GUID but do not cache this. try { - reader = Application.SqlHelper.ExecuteReader(sql, - Application.SqlHelper.CreateParameter("@contentTypeAlias", contentTypeAlias), - Application.SqlHelper.CreateParameter("@propertyAlias", propertyTypeAlias) - ); - if (reader.Read()) - { - if (!reader.IsNull("controlId")) - controlId = reader.GetGuid("controlId"); - else if (!reader.IsNull("masterAlias") && !String.IsNullOrEmpty(reader.GetString("masterAlias"))) - { - controlId = GetDataType(reader.GetString("masterAlias"), propertyTypeAlias); - } + return PropertyTypeCache.GetOrAdd( + key, + tuple => + { + //Instead of going via API, run this query to find the control type + //by-passes a lot of queries just to determine if this is a true/false data type - } - } - catch (UmbracoException) - { - _propertyTypeCache.Add(key, controlId); - } - finally - { - if (reader != null) - { - reader.Close(); - } - } + //This SQL returns a larger recordset than intended + //causing controlId to sometimes be null instead of correct + //because all properties for the type are returned + //side effect of changing inner join to left join when adding masterContentType + //string sql = "select " + + // "cmsDataType.controlId, masterContentType.alias as masterAlias " + + // "from " + + // "cmsContentType " + + // "inner join cmsPropertyType on (cmsContentType.nodeId = cmsPropertyType.contentTypeId) " + + // "left join cmsDataType on (cmsPropertyType.dataTypeId = cmsDataType.nodeId) and cmsPropertyType.Alias = @propertyAlias " + + // "left join cmsContentType masterContentType on masterContentType.nodeid = cmsContentType.masterContentType " + + // "where cmsContentType.alias = @contentTypeAlias"; - //add to cache - if (!_propertyTypeCache.ContainsKey(key)) - { - _propertyTypeCache.Add(key, controlId); - } - return controlId; + //this SQL correctly returns a single row when the property exists, but still returns masterAlias if it doesn't + var sql = "select cmsDataType.controlId, masterContentType.alias as masterAlias " + + "from " + + "cmsContentType " + + "left join cmsPropertyType on (cmsContentType.nodeId = cmsPropertyType.contentTypeId and cmsPropertyType.Alias = @propertyAlias) " + + "left join cmsDataType on (cmsPropertyType.dataTypeId = cmsDataType.nodeId) " + + "left join cmsContentType masterContentType on masterContentType.nodeid = cmsContentType.masterContentType " + + "where " + + "cmsContentType.alias = @contentTypeAlias"; + //Ensure that getdatatype doesn't throw an exception + //http://our.umbraco.org/forum/developers/razor/18085-Access-custom-node-properties-with-Razor + + //grab the controlid or test for parent + var controlId = Guid.Empty; + using (var reader = SqlHelper.ExecuteReader( + sql, + SqlHelper.CreateParameter("@contentTypeAlias", contentTypeAlias), + SqlHelper.CreateParameter("@propertyAlias", propertyTypeAlias) + )) + { + if (reader.Read()) + { + if (!reader.IsNull("controlId")) + { + controlId = reader.GetGuid("controlId"); + } + else if (!reader.IsNull("masterAlias") && !String.IsNullOrEmpty(reader.GetString("masterAlias"))) + { + controlId = GetDataType(reader.GetString("masterAlias"), propertyTypeAlias); + } + } + } + return controlId; + }); + } + catch (Exception ex) + { + LogHelper.Error("An error occurred in GetDataType", ex); + return Guid.Empty; + } } @@ -243,32 +209,10 @@ namespace umbraco.cms.businesslogic /// public static ContentType GetContentType(int id) { - return Cache.GetCacheItem(string.Format("UmbracoContentType{0}", id.ToString()), - m_Locker, - TimeSpan.FromMinutes(30), - delegate - { - return new ContentType(id); - }); - } - - /// - /// If true, this instance uses default umbraco data only. - /// - /// The ct. - /// - private static bool usesUmbracoDataOnly(ContentType ct) - { - bool retVal = true; - foreach (PropertyType pt in ct.PropertyTypes) - { - if (!DataTypeDefinition.IsDefaultData(pt.DataTypeDefinition.DataType.Data)) - { - retVal = false; - break; - } - } - return retVal; + return ApplicationContext.Current.ApplicationCache.GetCacheItem + (string.Format("UmbracoContentType{0}", id), + TimeSpan.FromMinutes(30), + () => new ContentType(id)); } // This is needed, because the Tab class is protected and as such it's not possible for @@ -315,29 +259,25 @@ namespace umbraco.cms.businesslogic /// The Id of the Tab on which the PropertyType is placed public static int getTabIdFromPropertyType(PropertyType pt) { - object tmp = SqlHelper.ExecuteScalar("Select tabId from cmsPropertyType where id = " + pt.Id.ToString()); + var tmp = SqlHelper.ExecuteScalar("Select tabId from cmsPropertyType where id = " + pt.Id.ToString()); if (tmp == DBNull.Value) return 0; - else return int.Parse(tmp.ToString()); + return int.Parse(tmp.ToString()); } #endregion #region Private Members - //private bool _optimizedMode = false; private string _alias; private string _iconurl; private string _description; private string _thumbnail; - private int m_masterContentType = 0; - private bool _isContainerContentType = false; - - private List m_AllowedChildContentTypeIDs = null; - private List m_VirtualTabs = null; - - private static readonly object propertyTypesCacheSyncLock = new object(); - + private int _masterContentType; + private bool _isContainerContentType; + private List _allowedChildContentTypeIDs; + private List _virtualTabs; + #endregion #region Public Properties @@ -371,17 +311,14 @@ namespace umbraco.cms.businesslogic { if (!_description.StartsWith("#")) return _description; - else + var lang = Language.GetByCultureCode(Thread.CurrentThread.CurrentCulture.Name); + if (lang != null) { - Language lang = Language.GetByCultureCode(Thread.CurrentThread.CurrentCulture.Name); - if (lang != null) + if (Dictionary.DictionaryItem.hasKey(_description.Substring(1, _description.Length - 1))) { - if (Dictionary.DictionaryItem.hasKey(_description.Substring(1, _description.Length - 1))) - { - var di = - new Dictionary.DictionaryItem(_description.Substring(1, _description.Length - 1)); - return di.Value(lang.id); - } + var di = + new Dictionary.DictionaryItem(_description.Substring(1, _description.Length - 1)); + return di.Value(lang.id); } } @@ -421,15 +358,7 @@ namespace umbraco.cms.businesslogic } } - ///// - ///// Gets or sets a value indicating whether [optimized mode]. - ///// - ///// true if [optimized mode]; otherwise, false. - //public bool OptimizedMode - //{ - // get { return _optimizedMode; } - // set { _optimizedMode = value; } - //} + /// /// Human readable name/label @@ -439,25 +368,20 @@ namespace umbraco.cms.businesslogic { get { - string tempText = base.Text; + var tempText = base.Text; if (!tempText.StartsWith("#")) return tempText; - else + var lang = Language.GetByCultureCode(Thread.CurrentThread.CurrentCulture.Name); + if (lang != null) { - Language lang = - Language.GetByCultureCode(Thread.CurrentThread.CurrentCulture.Name); - if (lang != null) + if (Dictionary.DictionaryItem.hasKey(tempText.Substring(1, tempText.Length - 1))) { - if (Dictionary.DictionaryItem.hasKey(tempText.Substring(1, tempText.Length - 1))) - { - Dictionary.DictionaryItem di = - new Dictionary.DictionaryItem(tempText.Substring(1, tempText.Length - 1)); - return di.Value(lang.id); - } + var di = new Dictionary.DictionaryItem(tempText.Substring(1, tempText.Length - 1)); + return di.Value(lang.id); } - - return "[" + tempText + "]"; } + + return "[" + tempText + "]"; } set { @@ -481,22 +405,23 @@ namespace umbraco.cms.businesslogic { get { - string cacheKey = GetPropertiesCacheKey(); + var cacheKey = GetPropertiesCacheKey(); - return Cache.GetCacheItem>(cacheKey, propertyTypesCacheSyncLock, + return ApplicationContext.Current.ApplicationCache.GetCacheItem( + cacheKey, TimeSpan.FromMinutes(15), - delegate + () => { - List result = new List(); - using (IRecordsReader dr = + var result = new List(); + using (var dr = SqlHelper.ExecuteReader( "select id from cmsPropertyType where contentTypeId = @ctId order by sortOrder", SqlHelper.CreateParameter("@ctId", Id))) { while (dr.Read()) { - int id = dr.GetInt("id"); - PropertyType pt = PropertyType.GetPropertyType(id); + var id = dr.GetInt("id"); + var pt = PropertyType.GetPropertyType(id); if (pt != null) result.Add(pt); } @@ -505,10 +430,7 @@ namespace umbraco.cms.businesslogic // Get Property Types from the master content type if (MasterContentType != 0) { - foreach (PropertyType pt in ContentType.GetContentType(MasterContentType).PropertyTypes) - { - result.Add(pt); - } + result.AddRange(GetContentType(MasterContentType).PropertyTypes); } return result; }); @@ -552,8 +474,7 @@ namespace umbraco.cms.businesslogic set { _iconurl = value; - SqlHelper.ExecuteNonQuery( - "update cmsContentType set icon='" + value + "' where nodeid = " + Id); + SqlHelper.ExecuteNonQuery("update cmsContentType set icon='" + value + "' where nodeid = " + Id); // Remove from cache FlushFromCache(Id); } @@ -567,11 +488,11 @@ namespace umbraco.cms.businesslogic { get { - return m_masterContentType; + return _masterContentType; } set { - m_masterContentType = value; + _masterContentType = value; SqlHelper.ExecuteNonQuery("update cmsContentType set masterContentType = @masterContentType where nodeId = @nodeId", SqlHelper.CreateParameter("@masterContentType", value), @@ -590,7 +511,7 @@ namespace umbraco.cms.businesslogic get { EnsureVirtualTabs(); - return m_VirtualTabs.ToArray(); + return _virtualTabs.ToArray(); } } @@ -601,10 +522,11 @@ namespace umbraco.cms.businesslogic public void ClearVirtualTabs() { // zb-00040 #29889 : clear the right cache! t.contentType is the ctype which _defines_ the tab, not the current one. - foreach (TabI t in getVirtualTabs) + //NOTE: SD: There is no cache to clear so this doesn't actually do anything + foreach (var t in getVirtualTabs) Tab.FlushCache(t.Id, Id); - m_VirtualTabs = null; + _virtualTabs = null; } /// @@ -616,29 +538,26 @@ namespace umbraco.cms.businesslogic get { //optimize this property so it lazy loads the data only one time. - if (m_AllowedChildContentTypeIDs == null) + if (_allowedChildContentTypeIDs == null) { - m_AllowedChildContentTypeIDs = new List(); - using (IRecordsReader dr = SqlHelper.ExecuteReader( - "Select AllowedId from cmsContentTypeAllowedContentType where id=" + - Id)) + _allowedChildContentTypeIDs = new List(); + using (var dr = SqlHelper.ExecuteReader("Select AllowedId from cmsContentTypeAllowedContentType where id=" + Id)) { while (dr.Read()) { - m_AllowedChildContentTypeIDs.Add(dr.GetInt("AllowedId")); + _allowedChildContentTypeIDs.Add(dr.GetInt("AllowedId")); } } } - return m_AllowedChildContentTypeIDs.ToArray(); + return _allowedChildContentTypeIDs.ToArray(); } set { - m_AllowedChildContentTypeIDs = value.ToList(); + _allowedChildContentTypeIDs = value.ToList(); - SqlHelper.ExecuteNonQuery( - "delete from cmsContentTypeAllowedContentType where id=" + Id); - foreach (int i in value) + SqlHelper.ExecuteNonQuery("delete from cmsContentTypeAllowedContentType where id=" + Id); + foreach (var i in value) { SqlHelper.ExecuteNonQuery( "insert into cmsContentTypeAllowedContentType (id,AllowedId) values (" + @@ -681,13 +600,13 @@ namespace umbraco.cms.businesslogic { var contentTypes = new List(); - using (IRecordsReader dr = - SqlHelper.ExecuteReader(m_SQLOptimizedGetAll.Trim(), SqlHelper.CreateParameter("@nodeObjectType", base.nodeObjectType))) + using (var dr = + SqlHelper.ExecuteReader(m_SQLOptimizedGetAll.Trim(), SqlHelper.CreateParameter("@nodeObjectType", nodeObjectType))) { while (dr.Read()) { //create the ContentType object without setting up - ContentType ct = new ContentType(dr.Get("id"), true); + var ct = new ContentType(dr.Get("id"), true); //populate it's CMSNode properties ct.PopulateCMSNodeFromReader(dr); //populate it's ContentType properties @@ -712,10 +631,10 @@ namespace umbraco.cms.businesslogic PropertyType pt = PropertyType.MakeNew(dt, this, Name, Alias); // Optimized call - populatePropertyData(pt, this.Id); + PopulatePropertyData(pt, Id); // Inherited content types (document types only) - populateMasterContentTypes(pt, this.Id); + PopulateMasterContentTypes(pt, Id); // foreach (Content c in Content.getContentOfContentType(this)) // c.addProperty(pt,c.Version); @@ -747,6 +666,7 @@ namespace umbraco.cms.businesslogic public void removePropertyTypeFromTab(PropertyType pt) { pt.TabId = 0; //this will set to null in the database. + // Remove from cache FlushFromCache(Id); } @@ -784,9 +704,7 @@ namespace umbraco.cms.businesslogic { //set each property on the tab to have a tab id of zero // zb-00036 #29889 : fix property types getter - this.getVirtualTabs.ToList() - .Where(x => x.Id == id) - .Single() + getVirtualTabs.ToList().Single(x => x.Id == id) .GetAllPropertyTypes() .ForEach(x => { @@ -819,7 +737,7 @@ namespace umbraco.cms.businesslogic /// Updates the sort order of the Tab /// /// The Id of the Tab to be updated - /// The new order number + /// The new order number public void SetTabSortOrder(int tabId, int sortOrder) { SqlHelper.ExecuteNonQuery( @@ -837,27 +755,13 @@ namespace umbraco.cms.businesslogic public PropertyType getPropertyType(string alias) { // NH 22-08-08, Get from the property type stack to ensure support of master document types - object o = this.PropertyTypes.Find(pt => pt.Alias == alias); - - //object o = SqlHelper.ExecuteScalar( - // "Select id from cmsPropertyType where contentTypeId=@contentTypeId And Alias=@alias", - // SqlHelper.CreateParameter("@contentTypeId", this.Id), - // SqlHelper.CreateParameter("@alias", alias)); + object o = PropertyTypes.Find(pt => pt.Alias == alias); if (o == null) { return null; } - else - { - return (PropertyType)o; - } - - //int propertyTypeId; - //if (!int.TryParse(o.ToString(), out propertyTypeId)) - // return null; - - //return PropertyType.GetPropertyType(propertyTypeId); + return (PropertyType)o; } /// @@ -869,9 +773,9 @@ namespace umbraco.cms.businesslogic FlushFromCache(Id); // Delete all propertyTypes - foreach (PropertyType pt in PropertyTypes) + foreach (var pt in PropertyTypes) { - if (pt.ContentTypeId == this.Id) + if (pt.ContentTypeId == Id) { pt.delete(); } @@ -880,7 +784,7 @@ namespace umbraco.cms.businesslogic // delete all tabs foreach (Tab t in getVirtualTabs.ToList()) { - if (t.ContentType == this.Id) + if (t.ContentType == Id) { t.Delete(); } @@ -907,7 +811,7 @@ namespace umbraco.cms.businesslogic _alias = dr.GetString("Alias"); _iconurl = dr.GetString("icon"); if (!dr.IsNull("masterContentType")) - m_masterContentType = dr.GetInt("masterContentType"); + _masterContentType = dr.GetInt("masterContentType"); if (!dr.IsNull("thumbnail")) _thumbnail = dr.GetString("thumbnail"); @@ -922,9 +826,7 @@ namespace umbraco.cms.businesslogic { base.setupNode(); - using (IRecordsReader dr = - SqlHelper.ExecuteReader("Select masterContentType,Alias,icon,thumbnail,description from cmsContentType where nodeid=" + Id) - ) + using (var dr = SqlHelper.ExecuteReader("Select masterContentType,Alias,icon,thumbnail,description from cmsContentType where nodeid=" + Id)) { if (dr.Read()) { @@ -949,12 +851,12 @@ namespace umbraco.cms.businesslogic /// /// Flushes the cache. /// - /// The id. + /// The id. public static void FlushFromCache(int id) - { - ContentType ct = new ContentType(id); - Cache.ClearCacheItem(string.Format("UmbracoContentType{0}", id)); - Cache.ClearCacheItem(ct.GetPropertiesCacheKey()); + { + var ct = new ContentType(id); + ApplicationContext.Current.ApplicationCache.ClearCacheItem(string.Format("UmbracoContentType{0}", id)); + ApplicationContext.Current.ApplicationCache.ClearCacheItem(ct.GetPropertiesCacheKey()); ct.ClearVirtualTabs(); //clear the content type from the property datatype cache used by razor @@ -972,12 +874,10 @@ namespace umbraco.cms.businesslogic protected internal void FlushAllFromCache() { - Cache.ClearCacheByKeySearch("UmbracoContentType"); - Cache.ClearCacheByKeySearch("ContentType_PropertyTypes_Content"); - - //clear the property datatype cache used by razor - _propertyTypeCache = new Dictionary, Guid>(); + ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch("UmbracoContentType"); + ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch("ContentType_PropertyTypes_Content"); + RemoveAllDataTypeCache(); ClearVirtualTabs(); } @@ -991,7 +891,7 @@ namespace umbraco.cms.businesslogic /// private string GetPropertiesCacheKey() { - return "ContentType_PropertyTypes_Content:" + this.Id; + return "ContentType_PropertyTypes_Content:" + Id; } @@ -1006,12 +906,12 @@ namespace umbraco.cms.businesslogic // If that happens, the m_VirtualTabs will contain duplicates. // We must prevent two threads from running InitializeVirtualTabs at the same time. // We must also prevent m_VirtualTabs from being modified while it is being populated. - if (m_VirtualTabs == null || m_VirtualTabs.Count == 0) + if (_virtualTabs == null || _virtualTabs.Count == 0) { lock (_virtualTabLoadLock) { //optimize, lazy load the data only one time - if (m_VirtualTabs == null || m_VirtualTabs.Count == 0) + if (_virtualTabs == null || _virtualTabs.Count == 0) { InitializeVirtualTabs(); } @@ -1027,8 +927,7 @@ namespace umbraco.cms.businesslogic { // While we are initialising, we should not use the class-scoped list, as it may be used by other threads var temporaryList = new List(); - using (IRecordsReader dr = SqlHelper.ExecuteReader( - string.Format( + using (var dr = SqlHelper.ExecuteReader(string.Format( "Select Id,text,sortOrder from cmsTab where contenttypeNodeId = {0} order by sortOrder", Id))) { @@ -1048,22 +947,22 @@ namespace umbraco.cms.businesslogic temporaryList.Sort((a, b) => a.SortOrder.CompareTo(b.SortOrder)); // now that we aren't going to modify the list, we can set it to the class-scoped variable. - m_VirtualTabs = temporaryList; + _virtualTabs = temporaryList; } - private void populateMasterContentTypes(PropertyType pt, int docTypeId) + private static void PopulateMasterContentTypes(PropertyType pt, int docTypeId) { - foreach (web.DocumentType docType in web.DocumentType.GetAllAsList()) + foreach (var docType in DocumentType.GetAllAsList()) { if (docType.MasterContentType == docTypeId) { - populatePropertyData(pt, docType.Id); - populateMasterContentTypes(pt, docType.Id); + PopulatePropertyData(pt, docType.Id); + PopulateMasterContentTypes(pt, docType.Id); } } } - private void populatePropertyData(PropertyType pt, int contentTypeId) + private static void PopulatePropertyData(PropertyType pt, int contentTypeId) { // NH: PropertyTypeId inserted directly into SQL instead of as a parameter for SQL CE 4 compatibility SqlHelper.ExecuteNonQuery( @@ -1151,8 +1050,7 @@ namespace umbraco.cms.businesslogic /// public class Tab : TabI { - private ContentType _contenttype; - private static object propertyTypesCacheSyncLock = new object(); + private readonly ContentType _contenttype; public static readonly string CacheKey = "Tab_PropertyTypes_Content:"; /// @@ -1173,8 +1071,7 @@ namespace umbraco.cms.businesslogic public static Tab GetTab(int id) { Tab tab = null; - using (IRecordsReader dr = SqlHelper.ExecuteReader( - string.Format( + using (var dr = SqlHelper.ExecuteReader(string.Format( "Select Id, text, contenttypeNodeId, sortOrder from cmsTab where Id = {0} order by sortOrder", id))) { @@ -1211,11 +1108,11 @@ namespace umbraco.cms.businesslogic if (includeInheritedProperties) { // start from contentTypeId and list all ctypes, going up - int c = contentTypeId; + var c = contentTypeId; while (c != 0) { ctypes.Add(c); - c = umbraco.cms.businesslogic.ContentType.GetContentType(c).MasterContentType; + c = businesslogic.ContentType.GetContentType(c).MasterContentType; } ctypes.Reverse(); // order from the top } @@ -1227,21 +1124,23 @@ namespace umbraco.cms.businesslogic foreach (var ctype in ctypes) { - var ptypes = Cache.GetCacheItem>( - generateCacheKey(Id, ctype), propertyTypesCacheSyncLock, TimeSpan.FromMinutes(10), - delegate - { - var tmp1 = new List(); - - using (IRecordsReader dr = SqlHelper.ExecuteReader(string.Format( - @"select id from cmsPropertyType where tabId = {0} and contentTypeId = {1} - order by sortOrder", _id, ctype))) + //copy local for use in delegate + var ctype1 = ctype; + var ptypes = ApplicationContext.Current.ApplicationCache.GetCacheItem( + GenerateCacheKey(Id, ctype), TimeSpan.FromMinutes(10), + () => { - while (dr.Read()) - tmp1.Add(PropertyType.GetPropertyType(dr.GetInt("id"))); - } - return tmp1; - }); + var tmp1 = new List(); + + using (var dr = SqlHelper.ExecuteReader(string.Format( + @"select id from cmsPropertyType where tabId = {0} and contentTypeId = {1} + order by sortOrder", _id, ctype1))) + { + while (dr.Read()) + tmp1.Add(PropertyType.GetPropertyType(dr.GetInt("id"))); + } + return tmp1; + }); tmp.AddRange(ptypes); } @@ -1254,7 +1153,7 @@ namespace umbraco.cms.businesslogic { var tmp = new List(); - using (IRecordsReader dr = SqlHelper.ExecuteReader(string.Format( + using (var dr = SqlHelper.ExecuteReader(string.Format( @"select id from cmsPropertyType where tabId = {0}", _id))) { while (dr.Read()) @@ -1270,7 +1169,7 @@ namespace umbraco.cms.businesslogic [Obsolete("Please use GetPropertyTypes() instead", false)] public PropertyType[] PropertyTypes { - get { return GetPropertyTypes(this.ContentType, true); } + get { return GetPropertyTypes(ContentType, true); } } @@ -1282,10 +1181,10 @@ namespace umbraco.cms.businesslogic /// public static void FlushCache(int id, int contentTypeId) { - Cache.ClearCacheItem(generateCacheKey(id, contentTypeId)); + ApplicationContext.Current.ApplicationCache.ClearCacheItem(GenerateCacheKey(id, contentTypeId)); } - private static string generateCacheKey(int tabId, int contentTypeId) + private static string GenerateCacheKey(int tabId, int contentTypeId) { return String.Format("{0}_{1}_{2}", CacheKey, tabId, contentTypeId); } @@ -1310,20 +1209,15 @@ namespace umbraco.cms.businesslogic { try { - string tempCaption = SqlHelper.ExecuteScalar("Select text from cmsTab where id = " + id.ToString()); + var tempCaption = SqlHelper.ExecuteScalar("Select text from cmsTab where id = " + id.ToString()); if (!tempCaption.StartsWith("#")) return tempCaption; - else + var lang = Language.GetByCultureCode(Thread.CurrentThread.CurrentCulture.Name); + if (lang != null) { - Language lang = - Language.GetByCultureCode(Thread.CurrentThread.CurrentCulture.Name); - if (lang != null) - return - new Dictionary.DictionaryItem(tempCaption.Substring(1, tempCaption.Length - 1)).Value( - lang.id); - else - return "[" + tempCaption + "]"; + return new Dictionary.DictionaryItem(tempCaption.Substring(1, tempCaption.Length - 1)).Value(lang.id); } + return "[" + tempCaption + "]"; } catch { @@ -1331,9 +1225,9 @@ namespace umbraco.cms.businesslogic } } - private int _id; + private readonly int _id; - private int? _sortOrder = null; + private int? _sortOrder; /// /// The sortorder of the tab @@ -1365,10 +1259,10 @@ namespace umbraco.cms.businesslogic // hence moving it up. if (SortOrder > 0) { - int newsortorder = SortOrder - 1; + var newsortorder = SortOrder - 1; // Find the tab to switch with - TabI[] Tabs = _contenttype.getVirtualTabs; - foreach (Tab t in Tabs) + var tabs = _contenttype.getVirtualTabs; + foreach (Tab t in tabs) { if (t.SortOrder == newsortorder) t.SortOrder = SortOrder; @@ -1385,12 +1279,12 @@ namespace umbraco.cms.businesslogic FixTabOrder(); // If this tab is not the last tab we can switch places with the next tab // hence moving it down. - TabI[] Tabs = _contenttype.getVirtualTabs; - if (SortOrder < Tabs.Length - 1) + var tabs = _contenttype.getVirtualTabs; + if (SortOrder < tabs.Length - 1) { - int newsortorder = SortOrder + 1; + var newsortorder = SortOrder + 1; // Find the tab to switch with - foreach (Tab t in Tabs) + foreach (Tab t in tabs) { if (t.SortOrder == newsortorder) t.SortOrder = SortOrder; @@ -1416,10 +1310,10 @@ namespace umbraco.cms.businesslogic /// private void FixTabOrder() { - TabI[] Tabs = _contenttype.getVirtualTabs; - for (int i = 0; i < Tabs.Length; i++) + var tabs = _contenttype.getVirtualTabs; + for (int i = 0; i < tabs.Length; i++) { - Tab t = (Tab)Tabs[i]; + var t = (Tab)tabs[i]; t.SortOrder = i; } } @@ -1442,7 +1336,7 @@ namespace umbraco.cms.businesslogic get { return _contenttype.Id; } } - private string _caption; + private readonly string _caption; /// /// The text on the tab @@ -1454,65 +1348,22 @@ namespace umbraco.cms.businesslogic { if (!_caption.StartsWith("#")) return _caption; - else + + var lang = Language.GetByCultureCode(Thread.CurrentThread.CurrentCulture.Name); + if (lang != null) { - Language lang = - Language.GetByCultureCode(Thread.CurrentThread.CurrentCulture.Name); - if (lang != null) + if (Dictionary.DictionaryItem.hasKey(_caption.Substring(1, _caption.Length - 1))) { - if (Dictionary.DictionaryItem.hasKey(_caption.Substring(1, _caption.Length - 1))) - { - Dictionary.DictionaryItem di = - new Dictionary.DictionaryItem(_caption.Substring(1, _caption.Length - 1)); - if (di != null) - return di.Value(lang.id); - } + var di = new Dictionary.DictionaryItem(_caption.Substring(1, _caption.Length - 1)); + return di.Value(lang.id); } - - return "[" + _caption + "]"; } + + return "[" + _caption + "]"; } } } #endregion - - ///// - ///// Analyzes the content types. - ///// - ///// Type of the object. - ///// if set to true [force update]. - //protected void AnalyzeContentTypes(Guid ObjectType, bool ForceUpdate) - //{ - // if (!_analyzedContentTypes.ContainsKey(ObjectType) || ForceUpdate) - // { - // using (IRecordsReader dr = SqlHelper.ExecuteReader( - // "select id from umbracoNode where nodeObjectType = @objectType", - // SqlHelper.CreateParameter("@objectType", ObjectType))) - // { - // while (dr.Read()) - // { - // ContentType ct = new ContentType(dr.GetInt("id")); - // if (!_optimizedContentTypes.ContainsKey(ct.UniqueId)) - // _optimizedContentTypes.Add(ct.UniqueId, false); - - // _optimizedContentTypes[ct.UniqueId] = usesUmbracoDataOnly(ct); - // } - // } - // } - //} - - ///// - ///// Determines whether this instance is optimized. - ///// - ///// - ///// true if this instance is optimized; otherwise, false. - ///// - //protected bool IsOptimized() - //{ - // return (bool) _optimizedContentTypes[UniqueId]; - //} - - } } diff --git a/src/umbraco.cms/businesslogic/language/Language.cs b/src/umbraco.cms/businesslogic/language/Language.cs index f98648e6d1..43f941f38d 100644 --- a/src/umbraco.cms/businesslogic/language/Language.cs +++ b/src/umbraco.cms/businesslogic/language/Language.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; using System.Data; using System.Globalization; using System.Xml; -using umbraco.cms.businesslogic.cache; +using Umbraco.Core; +using Umbraco.Core.Logging; using umbraco.DataLayer; using umbraco.BusinessLogic; using System.Linq; -using System.Runtime.CompilerServices; namespace umbraco.cms.businesslogic.language { @@ -27,14 +27,12 @@ namespace umbraco.cms.businesslogic.language private string _name = ""; private string _friendlyName; private string _cultureAlias; + private static readonly object Locker = new object(); #endregion #region Constants and static members - - private static object getLanguageSyncLock = new object(); - private static readonly string UmbracoLanguageCacheKey = "UmbracoPropertyTypeCache"; - - private const int DefaultLanguageId = 1; + + private const string UmbracoLanguageCacheKey = "UmbracoPropertyTypeCache"; /// /// Gets the SQL helper. @@ -47,8 +45,6 @@ namespace umbraco.cms.businesslogic.language protected internal const string m_SQLOptimizedGetAll = @"select * from umbracoLanguage"; - private static readonly object m_Locker = new object(); - #endregion #region Constructors @@ -59,9 +55,7 @@ namespace umbraco.cms.businesslogic.language /// The id. public Language(int id) { - var lang = GetAllAsList() - .Where(x => x.id == id) - .SingleOrDefault(); + var lang = GetAllAsList().SingleOrDefault(x => x.id == id); if (lang == null) { throw new ArgumentException("No language found with the specified id"); @@ -84,27 +78,39 @@ namespace umbraco.cms.businesslogic.language /// /// Creates a new language given the culture code - ie. da-dk (denmark) /// - /// Culturecode of the language - public static void MakeNew(string CultureCode) + /// Culturecode of the language + public static void MakeNew(string cultureCode) { - if (new CultureInfo(CultureCode) != null) + lock (Locker) { - SqlHelper.ExecuteNonQuery( - "insert into umbracoLanguage (languageISOCode) values (@CultureCode)", - SqlHelper.CreateParameter("@CultureCode", CultureCode)); + var culture = GetCulture(cultureCode); + if (culture != null) + { + //insert it + SqlHelper.ExecuteNonQuery( + "insert into umbracoLanguage (languageISOCode) values (@CultureCode)", + SqlHelper.CreateParameter("@CultureCode", cultureCode)); - InvalidateCache(); + InvalidateCache(); - NewEventArgs e = new NewEventArgs(); - GetByCultureCode(CultureCode).OnNew(e); + //get it's id + var newId = SqlHelper.ExecuteScalar("SELECT MAX(id) FROM umbracoLanguage WHERE languageISOCode=@cultureCode", SqlHelper.CreateParameter("@cultureCode", cultureCode)); + + //load it and raise events + using (var dr = SqlHelper.ExecuteReader(string.Format("{0} where id = {1}", m_SQLOptimizedGetAll, newId))) + { + while (dr.Read()) + { + + var ct = new Language(); + ct.PopulateFromReader(dr); + ct.OnNew(new NewEventArgs()); + } + } + } } } - private static void InvalidateCache() - { - Cache.ClearCacheItem(UmbracoLanguageCacheKey); - } - /// /// Method for accessing all installed languagess /// @@ -117,6 +123,11 @@ namespace umbraco.cms.businesslogic.language } } + private static void InvalidateCache() + { + ApplicationContext.Current.ApplicationCache.ClearCacheItem(UmbracoLanguageCacheKey); + } + /// /// Returns all installed languages /// @@ -126,40 +137,47 @@ namespace umbraco.cms.businesslogic.language /// public static IEnumerable GetAllAsList() { - return Cache.GetCacheItem>(UmbracoLanguageCacheKey, getLanguageSyncLock, TimeSpan.FromMinutes(60), - delegate - { - var languages = new List(); - - using (IRecordsReader dr = SqlHelper.ExecuteReader(m_SQLOptimizedGetAll)) + return ApplicationContext.Current.ApplicationCache.GetCacheItem>( + UmbracoLanguageCacheKey, TimeSpan.FromMinutes(60), + () => { - while (dr.Read()) + var languages = new List(); + using (var dr = SqlHelper.ExecuteReader(m_SQLOptimizedGetAll)) { - //create the ContentType object without setting up - Language ct = new Language(); - ct.PopulateFromReader(dr); - languages.Add(ct); + while (dr.Read()) + { + //create the ContentType object without setting up + var ct = new Language(); + ct.PopulateFromReader(dr); + languages.Add(ct); + } } - } - return languages; - }); + return languages; + }); } /// /// Gets the language by its culture code, if no language is found, null is returned /// - /// The culture code. + /// The culture code. /// - public static Language GetByCultureCode(String cultureCode) + public static Language GetByCultureCode(string cultureCode) { - if (new CultureInfo(cultureCode) != null) - { - return GetAllAsList() - .Where(x => x.CultureAlias == cultureCode) - .SingleOrDefault(); - } + return GetAllAsList().SingleOrDefault(x => x.CultureAlias == cultureCode); + } - return null; + private static CultureInfo GetCulture(string cultureCode) + { + try + { + var culture = new CultureInfo(cultureCode); + return culture; + } + catch (Exception ex) + { + LogHelper.Error("Could not find the culture " + cultureCode, ex); + return null; + } } /// @@ -169,16 +187,13 @@ namespace umbraco.cms.businesslogic.language /// public static Language Import(XmlNode xmlData) { - string cA = xmlData.Attributes["CultureAlias"].Value; - if (Language.GetByCultureCode(cA) == null) + var cA = xmlData.Attributes["CultureAlias"].Value; + if (GetByCultureCode(cA) == null) { - Language.MakeNew(cA); - return Language.GetByCultureCode(cA); - } - else - { - return null; + MakeNew(cA); + return GetByCultureCode(cA); } + return null; } #endregion @@ -204,7 +219,7 @@ namespace umbraco.cms.businesslogic.language SqlHelper.ExecuteNonQuery( "update umbracoLanguage set languageISOCode = @cultureAlias where id = @id", SqlHelper.CreateParameter("@id", id), SqlHelper.CreateParameter("@cultureAlias", _cultureAlias)); - updateNames(); + UpdateNames(); } } @@ -248,7 +263,7 @@ namespace umbraco.cms.businesslogic.language /// public virtual void Save() { - SaveEventArgs e = new SaveEventArgs(); + var e = new SaveEventArgs(); FireBeforeSave(e); if (!e.Cancel) @@ -267,40 +282,36 @@ namespace umbraco.cms.businesslogic.language /// You cannot delete the default language: en-US, this is installed by default and is required. /// public void Delete() - { - - - //if (this.id == DefaultLanguageId) - //{ - // throw new InvalidOperationException("You cannot delete the default language: en-US"); - //} - - - if (SqlHelper.ExecuteScalar("SELECT count(id) FROM umbracoDomains where domainDefaultLanguage = @id", - SqlHelper.CreateParameter("@id", id)) == 0) + { + lock (Locker) { - - DeleteEventArgs e = new DeleteEventArgs(); - FireBeforeDelete(e); - - if (!e.Cancel) + if (SqlHelper.ExecuteScalar("SELECT count(id) FROM umbracoDomains where domainDefaultLanguage = @id", + SqlHelper.CreateParameter("@id", id)) == 0) { - //remove the dictionary entries first - Item.RemoveByLanguage(id); - InvalidateCache(); + var e = new DeleteEventArgs(); + FireBeforeDelete(e); - SqlHelper.ExecuteNonQuery("delete from umbracoLanguage where id = @id", - SqlHelper.CreateParameter("@id", id)); - - FireAfterDelete(e); + if (!e.Cancel) + { + //remove the dictionary entries first + Item.RemoveByLanguage(id); + + InvalidateCache(); + + SqlHelper.ExecuteNonQuery("delete from umbracoLanguage where id = @id", + SqlHelper.CreateParameter("@id", id)); + + FireAfterDelete(e); + } } - } - else - { - Log.Add(LogTypes.Error, umbraco.BasePages.UmbracoEnsuredPage.CurrentUser, -1, "Could not remove Language " + _friendlyName + " because it's attached to a node"); - throw new DataException("Cannot remove language " + _friendlyName + " because it's attached to a domain on a node"); - } + else + { + var e = new DataException("Cannot remove language " + _friendlyName + " because it's attached to a domain on a node"); + LogHelper.Error("Cannot remove language " + _friendlyName + " because it's attached to a domain on a node", e); + throw e; + } + } } /// @@ -308,12 +319,12 @@ namespace umbraco.cms.businesslogic.language /// /// The xml document. /// - public System.Xml.XmlNode ToXml(XmlDocument xd) + public XmlNode ToXml(XmlDocument xd) { - XmlNode language = xd.CreateElement("Language"); - language.Attributes.Append(xmlHelper.addAttribute(xd, "Id", this.id.ToString())); - language.Attributes.Append(xmlHelper.addAttribute(xd, "CultureAlias", this.CultureAlias)); - language.Attributes.Append(xmlHelper.addAttribute(xd, "FriendlyName", this.FriendlyName)); + var language = xd.CreateElement("Language"); + language.Attributes.Append(XmlHelper.AddAttribute(xd, "Id", id.ToString())); + language.Attributes.Append(XmlHelper.AddAttribute(xd, "CultureAlias", CultureAlias)); + language.Attributes.Append(XmlHelper.AddAttribute(xd, "FriendlyName", FriendlyName)); return language; } @@ -326,17 +337,17 @@ namespace umbraco.cms.businesslogic.language _id = Convert.ToInt32(dr.GetShort("id")); _cultureAlias = dr.GetString("languageISOCode"); - updateNames(); + UpdateNames(); } #endregion #region Private methods - private void updateNames() + private void UpdateNames() { try { - CultureInfo ci = new CultureInfo(_cultureAlias); + var ci = new CultureInfo(_cultureAlias); _friendlyName = ci.DisplayName; } catch From a638488eb7ba3a8cf6185c2f036600bb84ce8fd9 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Mon, 1 Apr 2013 23:30:19 +0600 Subject: [PATCH 10/16] Fixes unit tests which require the ApplicationContext.Current singleton to be setup --- .../PublishedContent/PublishedContentTestBase.cs | 4 ++-- src/Umbraco.Tests/Routing/UmbracoModuleTests.cs | 3 --- src/Umbraco.Tests/TestHelpers/BaseWebTest.cs | 2 ++ 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs index 311cb1f391..3b1c328731 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs @@ -16,7 +16,7 @@ namespace Umbraco.Tests.PublishedContent public override void Initialize() { base.Initialize(); - + UmbracoSettings.SettingsFilePath = Core.IO.IOHelper.MapPath(Core.IO.SystemDirectories.Config + Path.DirectorySeparatorChar, false); PropertyEditorValueConvertersResolver.Current = new PropertyEditorValueConvertersResolver( @@ -47,7 +47,7 @@ namespace Umbraco.Tests.PublishedContent public override void TearDown() { base.TearDown(); - + PropertyEditorValueConvertersResolver.Reset(); PublishedContentStoreResolver.Reset(); PublishedMediaStoreResolver.Reset(); diff --git a/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs b/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs index 02cd000239..12329efacb 100644 --- a/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs +++ b/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs @@ -51,9 +51,6 @@ namespace Umbraco.Tests.Routing { base.Initialize(); - //the module requires that the singleton is setup - ApplicationContext.Current = ApplicationContext; - //create the module _module = new UmbracoModule(); diff --git a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs index 757f83d9fc..cefd53fafd 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs @@ -33,6 +33,8 @@ namespace Umbraco.Tests.TestHelpers TestHelper.InitializeDatabase(); Resolution.Freeze(); ApplicationContext = new ApplicationContext() { IsReady = true }; + //init the singleton too! + ApplicationContext.Current = ApplicationContext; //we need to clear out all currently created template files var masterPages = new DirectoryInfo(IOHelper.MapPath(SystemDirectories.Masterpages)); masterPages.GetFiles().ForEach(x => x.Delete()); From 39edb9b7e20e7659ba5296c61dd7e3929d969c08 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 2 Apr 2013 08:07:18 -0200 Subject: [PATCH 11/16] Fixes U4-2032 Preview for an RTE field shows published content instead of actual preview --- .../umbraco/templateControls/ItemRenderer.cs | 36 +++---------------- 1 file changed, 4 insertions(+), 32 deletions(-) diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs index de2149b1c4..3688230153 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs @@ -88,46 +88,18 @@ namespace umbraco.presentation.templateControls /// A string of field contents (macros not parsed) protected virtual string GetFieldContents(Item item) { - string tempElementContent = String.Empty; + var tempElementContent = string.Empty; // if a nodeId is specified we should get the data from another page than the current one - if (!String.IsNullOrEmpty(item.NodeId)) + if (string.IsNullOrEmpty(item.NodeId) == false) { - int? tempNodeId = item.GetParsedNodeId(); + var tempNodeId = item.GetParsedNodeId(); if (tempNodeId != null && tempNodeId.Value != 0) { - //moved the following from the catch block up as this will allow fallback options alt text etc to work - - page itemPage = new page(content.Instance.XmlContent.GetElementById(tempNodeId.ToString())); + var itemPage = new page(Umbraco.Web.UmbracoContext.Current.GetXml().GetElementById(tempNodeId.ToString())); tempElementContent = new item(itemPage.Elements, item.LegacyAttributes).FieldContent; - - /*removed as would fail as there is a incorrect cast in the method called. - Also the following code does not respect any of Umbraco Items fallback and formatting options */ - - //string currentField = helper.FindAttribute(item.LegacyAttributes, "field"); - // check for a cached instance of the content - //object contents = GetContentFromCache(tempNodeId.Value, currentField); - //if (contents != null) - // tempElementContent = (string)contents; - //else - //{ - // // as the field can be used for both documents, media and even members we'll use the - // // content class to lookup field items - // try - // { - // tempElementContent = GetContentFromDatabase(item.LegacyAttributes, tempNodeId.Value, currentField); - // } - // catch - // { - // // content was not found in property fields, - // // so the last place to look for is page fields - // page itemPage = new page(content.Instance.XmlContent.GetElementById(tempNodeId.ToString())); - // tempElementContent = new item(itemPage.Elements, item.LegacyAttributes).FieldContent; - // } - //} } - } else { From b9d7f0c5a5a7dbb3300192e04a4d54118a8a742c Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Tue, 2 Apr 2013 22:06:15 +0600 Subject: [PATCH 12/16] Fixes merge issues, merge ensures that js error is fixed and that thread-safe caching is in place in the ContentType.cs class. --- .../Configuration/UmbracoSettings.cs | 37 +----- src/Umbraco.Core/Umbraco.Core.csproj | 1 - .../controls/ContentTypeControlNew.ascx.cs | 42 +------ .../umbraco/templateControls/ItemRenderer.cs | 8 +- src/umbraco.cms/businesslogic/ContentType.cs | 108 ++++++++---------- 5 files changed, 51 insertions(+), 145 deletions(-) diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings.cs b/src/Umbraco.Core/Configuration/UmbracoSettings.cs index c841eb0674..34191ce52d 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings.cs @@ -1250,42 +1250,7 @@ namespace Umbraco.Core.Configuration return _macroErrorBehaviour.Value; } } - - private static IconPickerBehaviour? _iconPickerBehaviour; - - /// - /// This configuration setting defines how to show icons in the document type editor. - /// - ShowDuplicates - Show duplicates in files and sprites. (default and current Umbraco 'normal' behaviour) - /// - HideSpriteDuplicates - Show files on disk and hide duplicates from the sprite - /// - HideFileDuplicates - Show files in the sprite and hide duplicates on disk - /// - /// MacroErrorBehaviour enum defining how to show icons in the document type editor. - public static IconPickerBehaviour IconPickerBehaviour - { - get - { - if (_iconPickerBehaviour == null) - { - try - { - var behaviour = IconPickerBehaviour.ShowDuplicates; - var value = GetKey("/settings/content/DocumentTypeIconList"); - if (value != null) - { - Enum.TryParse(value, true, out behaviour); - } - _iconPickerBehaviour = behaviour; - } - catch (Exception ex) - { - LogHelper.Error("Could not load /settings/content/DocumentTypeIconList from umbracosettings.config", ex); - _iconPickerBehaviour = IconPickerBehaviour.ShowDuplicates; - } - } - return _iconPickerBehaviour.Value; - } - } - + private static IconPickerBehaviour? _iconPickerBehaviour; /// diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index f8f362f6c1..e48aa79ab6 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -112,7 +112,6 @@ - diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs index b0c270fd87..3cef15a8b4 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -387,47 +387,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); private static string FileNameToIconFileName(FileInfo file) { return file.Name.Substring(0, file.Name.LastIndexOf(".", StringComparison.Ordinal)).ToLowerInvariant(); - } - - private void AddSpriteListItem(string iconClass, ICollection listOfIcons) - { - var li = new ListItem( - helper.SpaceCamelCasing((iconClass.Substring(1, iconClass.Length - 1))) - .Replace("Spr Tree", "") - .Trim(), iconClass); - - li.Attributes.Add("class", "spriteBackground sprTree " + iconClass.Trim('.')); - li.Attributes.Add("style", "padding-left:24px !important; background-repeat:no-repeat; width:auto; height:auto;"); - - AddListItem(listOfIcons, li); - } - - private void AddFileListItem(string fileName, string listItemValue, ICollection listOfIcons) - { - var li = new ListItem(fileName, fileName); - - li.Attributes.Add("title", listItemValue); - - AddListItem(listOfIcons, li); - } - - private void AddListItem(ICollection listOfIcons, ListItem li) - { - if (this.Page.IsPostBack == false && li.Value == _contentType.IconUrl) - li.Selected = true; - - listOfIcons.Add(li); - } - - private static string IconClassToIconFileName(string iconClass) - { - return iconClass.Substring(1, iconClass.Length - 1).ToLowerInvariant().Replace("sprTree".ToLowerInvariant(), ""); - } - - private static string FileNameToIconFileName(FileInfo file) - { - return file.Name.Substring(0, file.Name.LastIndexOf(".", StringComparison.Ordinal)).ToLowerInvariant(); - } + } #endregion diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs index 4bbc0e7279..4bca0869a9 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs @@ -100,13 +100,7 @@ namespace umbraco.presentation.templateControls { //moved the following from the catch block up as this will allow fallback options alt text etc to work var itemPage = new page(Umbraco.Web.UmbracoContext.Current.GetXml().GetElementById(tempNodeId.ToString())); - //get the publishedcontent item - var publishedContent = PublishedContentStoreResolver.Current.PublishedContentStore.GetDocumentById( - Umbraco.Web.UmbracoContext.Current, - tempNodeId.Value); - - var itemPage = new page(publishedContent); - tempElementContent = new item(publishedContent, itemPage.Elements, item.LegacyAttributes).FieldContent; + tempElementContent = new item(itemPage.Elements, item.LegacyAttributes).FieldContent; } } else diff --git a/src/umbraco.cms/businesslogic/ContentType.cs b/src/umbraco.cms/businesslogic/ContentType.cs index cedd7fd40c..6e2f972d43 100644 --- a/src/umbraco.cms/businesslogic/ContentType.cs +++ b/src/umbraco.cms/businesslogic/ContentType.cs @@ -8,6 +8,8 @@ using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence.Caching; +using umbraco.cms.businesslogic.cache; +using umbraco.cms.businesslogic.propertytype; using umbraco.cms.businesslogic.web; using umbraco.DataLayer; using DataTypeDefinition = umbraco.cms.businesslogic.datatype.DataTypeDefinition; @@ -144,38 +146,23 @@ namespace umbraco.cms.businesslogic { var key = new System.Tuple(contentTypeAlias, propertyTypeAlias); - //NOTE: We only have a try/catch here for legacy reasons, I don't see any reason to have it - // but it was here before so we'll need to keep it for this legacy version. - // If an error occurs, we return an empty GUID but do not cache this. - try - { - return PropertyTypeCache.GetOrAdd( - key, - tuple => + + return PropertyTypeCache.GetOrAdd( + key, + tuple => + { + // With 4.10 we can't do this via direct SQL as we have content type mixins + var controlId = Guid.Empty; + var ct = GetByAlias(contentTypeAlias); + PropertyType pt = ct.getPropertyType(propertyTypeAlias); + if (pt != null) { - // With 4.10 we can't do this via direct SQL as we have content type mixins - var controlId = Guid.Empty; - ContentType ct = GetByAlias(contentTypeAlias); - PropertyType pt = ct.getPropertyType(propertyTypeAlias); - if (pt != null) - SqlHelper.CreateParameter("@propertyAlias", propertyTypeAlias) - )) - { - } - { - controlId = pt.DataTypeDefinition.DataType.Id; - } - return controlId; - }); - catch (Exception ex) - //add to cache (even if empty!) - { - LogHelper.Error("An error occurred in GetDataType", ex); - return Guid.Empty; - } + controlId = pt.DataTypeDefinition.DataType.Id; + } + return controlId; + }); } - /// /// Gets the type of the content. /// @@ -510,39 +497,41 @@ namespace umbraco.cms.businesslogic cacheKey, TimeSpan.FromMinutes(15), () => - { - //MCH NOTE: For the timing being I have changed this to a dictionary to ensure that property types - //aren't added multiple times through the MasterContentType structure, because each level loads - //its own + inherited property types, which is wrong. Once we are able to fully switch to the new api - //this should no longer be a problem as the composition always contains a correct list of property types. - var result = new Dictionary(); - SqlHelper.ExecuteReader( - "select id from cmsPropertyType where contentTypeId = @ctId order by sortOrder", - SqlHelper.CreateParameter("@ctId", Id))) { - while (dr.Read()) + //MCH NOTE: For the timing being I have changed this to a dictionary to ensure that property types + //aren't added multiple times through the MasterContentType structure, because each level loads + //its own + inherited property types, which is wrong. Once we are able to fully switch to the new api + //this should no longer be a problem as the composition always contains a correct list of property types. + var result = new Dictionary(); + using (IRecordsReader dr = + SqlHelper.ExecuteReader( + "select id from cmsPropertyType where contentTypeId = @ctId order by sortOrder", + SqlHelper.CreateParameter("@ctId", Id))) { - var id = dr.GetInt("id"); - var pt = PropertyType.GetPropertyType(id); - if (pt != null) - result.Add(pt.Id, pt); - } - } - - // Get Property Types from the master content type - if (MasterContentTypes.Count > 0) - { - foreach (var mct in MasterContentTypes) - var pts = ContentType.GetContentType(mct).PropertyTypes; - foreach (PropertyType pt in pts) + while (dr.Read()) { - if(result.ContainsKey(pt.Id) == false) + int id = dr.GetInt("id"); + PropertyType pt = PropertyType.GetPropertyType(id); + if (pt != null) result.Add(pt.Id, pt); } } - } - return result.Select(x => x.Value).ToList(); - }); + + // Get Property Types from the master content type + if (MasterContentTypes.Count > 0) + { + foreach (var mct in MasterContentTypes) + { + var pts = GetContentType(mct).PropertyTypes; + foreach (var pt in pts) + { + if (result.ContainsKey(pt.Id) == false) + result.Add(pt.Id, pt); + } + } + } + return result.Select(x => x.Value).ToList(); + }); } } @@ -1075,7 +1064,8 @@ namespace umbraco.cms.businesslogic } // TODO: Load master content types - SqlHelper.ExecuteReader("Select allowAtRoot, isContainer, Alias,icon,thumbnail,description from cmsContentType where nodeid=" + Id) + using (var dr = SqlHelper.ExecuteReader("Select allowAtRoot, isContainer, Alias,icon,thumbnail,description from cmsContentType where nodeid=" + Id) + ) { if (dr.Read()) { @@ -1191,7 +1181,7 @@ namespace umbraco.cms.businesslogic temporaryList.Sort((a, b) => a.SortOrder.CompareTo(b.SortOrder)); // now that we aren't going to modify the list, we can set it to the class-scoped variable. - m_VirtualTabs = temporaryList.DistinctBy(x => x.Id).ToList(); + _virtualTabs = temporaryList.DistinctBy(x => x.Id).ToList(); } private static void PopulateMasterContentTypes(PropertyType pt, int docTypeId) @@ -1347,8 +1337,6 @@ namespace umbraco.cms.businesslogic // we need to var contentType = businesslogic.ContentType.GetContentType(contentTypeId); return pts.Where(x => contentType.MasterContentTypes.Contains(x.ContentTypeId) || x.ContentTypeId == contentTypeId).ToArray(); - GenerateCacheKey(Id, ctype), TimeSpan.FromMinutes(10), - () => } return pts.Where(x => x.ContentTypeId == contentTypeId).ToArray(); From 182107286ca4d2623cf45cda969fc4be3dd899dc Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Tue, 2 Apr 2013 23:08:43 +0600 Subject: [PATCH 13/16] Fixes merge issues --- src/Umbraco.Tests/TestHelpers/BaseWebTest.cs | 4 +--- .../XmlPublishedCache/PublishedContentCache.cs | 2 +- src/Umbraco.Web/Umbraco.Web.csproj | 3 --- src/Umbraco.Web/UmbracoContext.cs | 5 +++-- .../umbraco/templateControls/ItemRenderer.cs | 5 ++++- src/umbraco.cms/businesslogic/language/Language.cs | 14 -------------- 6 files changed, 9 insertions(+), 24 deletions(-) diff --git a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs index 71c1758174..95e89468c3 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs @@ -29,9 +29,7 @@ namespace Umbraco.Tests.TestHelpers { base.Initialize(); } - - //init the singleton too! - ApplicationContext.Current = ApplicationContext; + [TearDown] public override void TearDown() { diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs index ea20f6bb04..b48d680918 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs @@ -334,7 +334,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache { if (_previewContent == null) { - _previewContent = new PreviewContent(user, new Guid(global::umbraco.BusinessLogic.StateHelper.Cookies.Preview.GetValue()), true); + _previewContent = new PreviewContent(user, new Guid(StateHelper.Cookies.Preview.GetValue()), true); if (_previewContent.ValidPreviewSet) _previewContent.LoadPreviewset(); } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index c4114799e9..220ea707f1 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -467,9 +467,6 @@ ASPXCodeBehind - - ASPXCodeBehind - ASPXCodeBehind diff --git a/src/Umbraco.Web/UmbracoContext.cs b/src/Umbraco.Web/UmbracoContext.cs index deba7751f5..3de2a014b4 100644 --- a/src/Umbraco.Web/UmbracoContext.cs +++ b/src/Umbraco.Web/UmbracoContext.cs @@ -5,6 +5,7 @@ using Umbraco.Core.Services; using Umbraco.Core.CodeAnnotations; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; +using Umbraco.Web.Security; using umbraco; using umbraco.IO; using umbraco.presentation; @@ -314,7 +315,7 @@ namespace Umbraco.Web { get { - return UmbracoEnsuredPage.CurrentUser; + return WebSecurity.CurrentUser; } } @@ -335,7 +336,7 @@ namespace Umbraco.Web return StateHelper.Cookies.Preview.HasValue // has preview cookie && UmbracoUser != null // has user - && !currentUrl.StartsWith(Umbraco.Core.IO.IOHelper.ResolveUrl(Umbraco.Core.IO.SystemDirectories.Umbraco)); // is not in admin UI + && !currentUrl.StartsWith(Core.IO.IOHelper.ResolveUrl(Core.IO.SystemDirectories.Umbraco)); // is not in admin UI } private HttpRequestBase GetRequestFromContext() diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs index 222c25b00f..0c328e17a2 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs @@ -10,6 +10,7 @@ using System.Xml; using Umbraco.Core.Macros; using Umbraco.Web; using Umbraco.Web.PublishedCache; +using Umbraco.Web.PublishedCache.XmlPublishedCache; using Umbraco.Web.Routing; using Umbraco.Web.Templates; using umbraco.cms.businesslogic; @@ -100,7 +101,9 @@ namespace umbraco.presentation.templateControls if (tempNodeId != null && tempNodeId.Value != 0) { //moved the following from the catch block up as this will allow fallback options alt text etc to work - var itemPage = new page(Umbraco.Web.UmbracoContext.Current.GetXml().GetElementById(tempNodeId.ToString())); + var xml = ((PublishedContentCache) PublishedContentCacheResolver.Current.ContentCache) + .GetXml(Umbraco.Web.UmbracoContext.Current); + var itemPage = new page(xml.GetElementById(tempNodeId.ToString())); tempElementContent = new item(itemPage.Elements, item.LegacyAttributes).FieldContent; } } diff --git a/src/umbraco.cms/businesslogic/language/Language.cs b/src/umbraco.cms/businesslogic/language/Language.cs index 17c90fc8a6..0618b9d7d4 100644 --- a/src/umbraco.cms/businesslogic/language/Language.cs +++ b/src/umbraco.cms/businesslogic/language/Language.cs @@ -105,15 +105,6 @@ namespace umbraco.cms.businesslogic.language } } } - } - { - - var ct = new Language(); - ct.PopulateFromReader(dr); - ct.OnNew(new NewEventArgs()); - } - } - } } } @@ -129,11 +120,6 @@ namespace umbraco.cms.businesslogic.language } } - private static void InvalidateCache() - { - ApplicationContext.Current.ApplicationCache.ClearCacheItem(UmbracoLanguageCacheKey); - } - /// /// Returns all installed languages /// From a4c9c3bfd9f3985981aea3393ce1fc94043e2614 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Wed, 3 Apr 2013 05:25:26 -0200 Subject: [PATCH 14/16] Updating EntityService and repository to add content and media specific properties to the UmbracoEntity for performance enhancements. Adding sample implementation in the BaseMediaTree but keeping it commented out as it won't work with the legacy events. And a bit of code cleanup --- src/Umbraco.Core/Models/UmbracoEntity.cs | 45 +++++++ .../Factories/UmbracoEntityFactory.cs | 5 +- .../Repositories/EntityRepository.cs | 123 +++++++++++------- src/Umbraco.Core/Services/EntityService.cs | 12 +- src/Umbraco.Tests/Services/BaseServiceTest.cs | 5 +- .../Services/EntityServiceTests.cs | 45 +++++++ .../umbraco/Trees/BaseMediaTree.cs | 95 +++++++++++++- .../umbraco/Trees/loadMedia.cs | 19 --- 8 files changed, 263 insertions(+), 86 deletions(-) diff --git a/src/Umbraco.Core/Models/UmbracoEntity.cs b/src/Umbraco.Core/Models/UmbracoEntity.cs index 4791606d2c..d87ec768f9 100644 --- a/src/Umbraco.Core/Models/UmbracoEntity.cs +++ b/src/Umbraco.Core/Models/UmbracoEntity.cs @@ -20,6 +20,8 @@ namespace Umbraco.Core.Models private bool _isPublished; private bool _isDraft; private bool _hasPendingChanges; + private string _contentTypeAlias; + private string _umbracoFile; private Guid _nodeObjectTypeId; private static readonly PropertyInfo CreatorIdSelector = ExpressionHelper.GetPropertyInfo(x => x.CreatorId); @@ -33,7 +35,11 @@ namespace Umbraco.Core.Models private static readonly PropertyInfo IsPublishedSelector = ExpressionHelper.GetPropertyInfo(x => x.IsPublished); private static readonly PropertyInfo IsDraftSelector = ExpressionHelper.GetPropertyInfo(x => x.IsDraft); private static readonly PropertyInfo HasPendingChangesSelector = ExpressionHelper.GetPropertyInfo(x => x.HasPendingChanges); + private static readonly PropertyInfo ContentTypeAliasSelector = ExpressionHelper.GetPropertyInfo(x => x.ContentTypeAlias); + private static readonly PropertyInfo ContentTypeIconUrlSelector = ExpressionHelper.GetPropertyInfo(x => x.ContentTypeIcon); + private static readonly PropertyInfo UmbracoFileSelector = ExpressionHelper.GetPropertyInfo(x => x.UmbracoFile); private static readonly PropertyInfo NodeObjectTypeIdSelector = ExpressionHelper.GetPropertyInfo(x => x.NodeObjectTypeId); + private string _contentTypeIcon; public UmbracoEntity() { @@ -187,6 +193,45 @@ namespace Umbraco.Core.Models } } + public string ContentTypeAlias + { + get { return _contentTypeAlias; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _contentTypeAlias = value; + return _contentTypeAlias; + }, _contentTypeAlias, ContentTypeAliasSelector); + } + } + + public string ContentTypeIcon + { + get { return _contentTypeIcon; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _contentTypeIcon = value; + return _contentTypeIcon; + }, _contentTypeIcon, ContentTypeIconUrlSelector); + } + } + + public string UmbracoFile + { + get { return _umbracoFile; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _umbracoFile = value; + return _umbracoFile; + }, _umbracoFile, UmbracoFileSelector); + } + } + public Guid NodeObjectTypeId { get { return _nodeObjectTypeId; } diff --git a/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs b/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs index e3fec16cf4..e2e319829b 100644 --- a/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs @@ -21,7 +21,10 @@ namespace Umbraco.Core.Persistence.Factories ParentId = dto.ParentId, Path = dto.Path, SortOrder = dto.SortOrder, - HasChildren = dto.Children > 0 + HasChildren = dto.Children > 0, + ContentTypeAlias = dto.Alias ?? string.Empty, + ContentTypeIcon = dto.IconUrl ?? string.Empty, + UmbracoFile = dto.UmbracoFile ?? string.Empty }; entity.IsPublished = dto.PublishedVersion != default(Guid) || diff --git a/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs b/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs index a4a0e08e5d..7fdec8702f 100644 --- a/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs @@ -58,8 +58,8 @@ namespace Umbraco.Core.Persistence.Repositories public virtual IUmbracoEntity Get(int id, Guid objectTypeId) { - bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document); - var sql = GetBaseWhere(GetBase, isContent, objectTypeId, id).Append(GetGroupBy(isContent)); + bool isContentOrMedia = objectTypeId == new Guid(Constants.ObjectTypes.Document) || objectTypeId == new Guid(Constants.ObjectTypes.Media); + var sql = GetBaseWhere(GetBase, isContentOrMedia, objectTypeId, id).Append(GetGroupBy(isContentOrMedia)); var nodeDto = _work.Database.FirstOrDefault(sql); if (nodeDto == null) return null; @@ -81,8 +81,8 @@ namespace Umbraco.Core.Persistence.Repositories } else { - bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document); - var sql = GetBaseWhere(GetBase, isContent, objectTypeId).Append(GetGroupBy(isContent)); + bool isContentOrMedia = objectTypeId == new Guid(Constants.ObjectTypes.Document) || objectTypeId == new Guid(Constants.ObjectTypes.Media); + var sql = GetBaseWhere(GetBase, isContentOrMedia, objectTypeId).Append(GetGroupBy(isContentOrMedia)); var dtos = _work.Database.Fetch(sql); var factory = new UmbracoEntityFactory(); @@ -111,10 +111,10 @@ namespace Umbraco.Core.Persistence.Repositories public virtual IEnumerable GetByQuery(IQuery query, Guid objectTypeId) { - bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document); - var sqlClause = GetBaseWhere(GetBase, isContent, objectTypeId); + bool isContentOrMedia = objectTypeId == new Guid(Constants.ObjectTypes.Document) || objectTypeId == new Guid(Constants.ObjectTypes.Media); + var sqlClause = GetBaseWhere(GetBase, isContentOrMedia, objectTypeId); var translator = new SqlTranslator(sqlClause, query); - var sql = translator.Translate().Append(GetGroupBy(isContent)); + var sql = translator.Translate().Append(GetGroupBy(isContentOrMedia)); var dtos = _work.Database.Fetch(sql); @@ -128,94 +128,110 @@ namespace Umbraco.Core.Persistence.Repositories #region Sql Statements - protected virtual Sql GetBase(bool isContent) + protected virtual Sql GetBase(bool isContentOrMedia) { var columns = new List { - "main.id", - "main.trashed", - "main.parentID", - "main.nodeUser", - "main.level", - "main.path", - "main.sortOrder", - "main.uniqueID", - "main.text", - "main.nodeObjectType", - "main.createDate", + "umbracoNode.id", + "umbracoNode.trashed", + "umbracoNode.parentID", + "umbracoNode.nodeUser", + "umbracoNode.level", + "umbracoNode.path", + "umbracoNode.sortOrder", + "umbracoNode.uniqueID", + "umbracoNode.text", + "umbracoNode.nodeObjectType", + "umbracoNode.createDate", "COUNT(parent.parentID) as children" }; - if (isContent) + if (isContentOrMedia) { columns.Add("published.versionId as publishedVerison"); columns.Add("latest.versionId as newestVersion"); + columns.Add("contenttype.alias"); + columns.Add("contenttype.icon"); + columns.Add("property.dataNvarchar as umbracoFile"); } var sql = new Sql() .Select(columns.ToArray()) - .From("umbracoNode main") - .LeftJoin("umbracoNode parent").On("parent.parentID = main.id"); + .From("umbracoNode umbracoNode") + .LeftJoin("umbracoNode parent").On("parent.parentID = umbracoNode.id"); - if (isContent) + if (isContentOrMedia) { - sql.LeftJoin("(SELECT nodeId, versionId FROM cmsDocument WHERE published = 1 GROUP BY nodeId, versionId) as published").On("main.id = published.nodeId"); - sql.LeftJoin("(SELECT nodeId, versionId FROM cmsDocument WHERE newest = 1 GROUP BY nodeId, versionId) as latest").On("main.id = latest.nodeId"); + sql.InnerJoin("cmsContent content").On("content.nodeId = umbracoNode.id") + .LeftJoin("cmsContentType contenttype").On("contenttype.nodeId = content.contentType") + .LeftJoin( + "(SELECT nodeId, versionId FROM cmsDocument WHERE published = 1 GROUP BY nodeId, versionId) as published") + .On("umbracoNode.id = published.nodeId") + .LeftJoin( + "(SELECT nodeId, versionId FROM cmsDocument WHERE newest = 1 GROUP BY nodeId, versionId) as latest") + .On("umbracoNode.id = latest.nodeId") + .LeftJoin( + "(SELECT contentNodeId, dataNvarchar FROM cmsPropertyData INNER JOIN cmsPropertyType ON cmsPropertyType.id = cmsPropertyData.propertytypeid"+ + " INNER JOIN cmsDataType ON cmsPropertyType.dataTypeId = cmsDataType.nodeId WHERE cmsDataType.controlId = '"+ Constants.PropertyEditors.UploadField +"') as property") + .On("umbracoNode.id = property.contentNodeId"); } return sql; } - protected virtual Sql GetBaseWhere(Func baseQuery, bool isContent, Guid id) + protected virtual Sql GetBaseWhere(Func baseQuery, bool isContentOrMedia, Guid id) { - var sql = baseQuery(isContent) - .Where("main.nodeObjectType = @NodeObjectType", new {NodeObjectType = id}); + var sql = baseQuery(isContentOrMedia) + .Where("umbracoNode.nodeObjectType = @NodeObjectType", new { NodeObjectType = id }); return sql; } - protected virtual Sql GetBaseWhere(Func baseQuery, bool isContent, int id) + protected virtual Sql GetBaseWhere(Func baseQuery, bool isContentOrMedia, int id) { - var sql = baseQuery(isContent) - .Where("main.id = @Id", new {Id = id}) - .Append(GetGroupBy(isContent)); + var sql = baseQuery(isContentOrMedia) + .Where("umbracoNode.id = @Id", new { Id = id }) + .Append(GetGroupBy(isContentOrMedia)); return sql; } - protected virtual Sql GetBaseWhere(Func baseQuery, bool isContent, Guid objectId, int id) + protected virtual Sql GetBaseWhere(Func baseQuery, bool isContentOrMedia, Guid objectId, int id) { - var sql = baseQuery(isContent) - .Where("main.id = @Id AND main.nodeObjectType = @NodeObjectType", + var sql = baseQuery(isContentOrMedia) + .Where("umbracoNode.id = @Id AND umbracoNode.nodeObjectType = @NodeObjectType", new {Id = id, NodeObjectType = objectId}); return sql; } - protected virtual Sql GetGroupBy(bool isContent) + protected virtual Sql GetGroupBy(bool isContentOrMedia) { var columns = new List { - "main.id", - "main.trashed", - "main.parentID", - "main.nodeUser", - "main.level", - "main.path", - "main.sortOrder", - "main.uniqueID", - "main.text", - "main.nodeObjectType", - "main.createDate" + "umbracoNode.id", + "umbracoNode.trashed", + "umbracoNode.parentID", + "umbracoNode.nodeUser", + "umbracoNode.level", + "umbracoNode.path", + "umbracoNode.sortOrder", + "umbracoNode.uniqueID", + "umbracoNode.text", + "umbracoNode.nodeObjectType", + "umbracoNode.createDate" }; - if (isContent) + if (isContentOrMedia) { columns.Add("published.versionId"); columns.Add("latest.versionId"); + columns.Add("contenttype.alias"); + columns.Add("contenttype.icon"); + columns.Add("property.dataNvarchar"); } var sql = new Sql() .GroupBy(columns.ToArray()) - .OrderBy("main.sortOrder"); + .OrderBy("umbracoNode.sortOrder"); return sql; } @@ -246,6 +262,15 @@ namespace Umbraco.Core.Persistence.Repositories [Column("newestVerison")] public Guid NewestVersion { get; set; } + + [Column("alias")] + public string Alias { get; set; } + + [Column("icon")] + public string IconUrl { get; set; } + + [Column("umbracoFile")] + public string UmbracoFile { get; set; } } #endregion } diff --git a/src/Umbraco.Core/Services/EntityService.cs b/src/Umbraco.Core/Services/EntityService.cs index 5e0b68b239..e8bd53e9c6 100644 --- a/src/Umbraco.Core/Services/EntityService.cs +++ b/src/Umbraco.Core/Services/EntityService.cs @@ -164,13 +164,13 @@ namespace Umbraco.Core.Services /// /// Gets a collection of children by the parents Id /// - /// Id of the parent to retrieve children for + /// Id of the parent to retrieve children for /// An enumerable list of objects - public virtual IEnumerable GetChildren(int id) + public virtual IEnumerable GetChildren(int parentId) { using (var repository = _repositoryFactory.CreateEntityRepository(_uowProvider.GetUnitOfWork())) { - var query = Query.Builder.Where(x => x.ParentId == id); + var query = Query.Builder.Where(x => x.ParentId == parentId); var contents = repository.GetByQuery(query); return contents; @@ -180,15 +180,15 @@ namespace Umbraco.Core.Services /// /// Gets a collection of children by the parents Id and UmbracoObjectType /// - /// Id of the parent to retrieve children for + /// Id of the parent to retrieve children for /// UmbracoObjectType of the children to retrieve /// An enumerable list of objects - public virtual IEnumerable GetChildren(int id, UmbracoObjectTypes umbracoObjectType) + public virtual IEnumerable GetChildren(int parentId, UmbracoObjectTypes umbracoObjectType) { var objectTypeId = umbracoObjectType.GetGuid(); using (var repository = _repositoryFactory.CreateEntityRepository(_uowProvider.GetUnitOfWork())) { - var query = Query.Builder.Where(x => x.ParentId == id); + var query = Query.Builder.Where(x => x.ParentId == parentId); var contents = repository.GetByQuery(query, objectTypeId); return contents; diff --git a/src/Umbraco.Tests/Services/BaseServiceTest.cs b/src/Umbraco.Tests/Services/BaseServiceTest.cs index 56b94dcbf1..cd4318b5a6 100644 --- a/src/Umbraco.Tests/Services/BaseServiceTest.cs +++ b/src/Umbraco.Tests/Services/BaseServiceTest.cs @@ -1,11 +1,8 @@ using System; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; -using umbraco.editorControls.tinyMCE3; -using umbraco.interfaces; namespace Umbraco.Tests.Services { @@ -26,7 +23,7 @@ namespace Umbraco.Tests.Services base.TearDown(); } - public void CreateTestData() + public virtual void CreateTestData() { //NOTE Maybe not the best way to create/save test data as we are using the services, which are being tested. diff --git a/src/Umbraco.Tests/Services/EntityServiceTests.cs b/src/Umbraco.Tests/Services/EntityServiceTests.cs index abf541883f..dce19cb80a 100644 --- a/src/Umbraco.Tests/Services/EntityServiceTests.cs +++ b/src/Umbraco.Tests/Services/EntityServiceTests.cs @@ -3,6 +3,7 @@ using System.Linq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Models; +using Umbraco.Tests.TestHelpers.Entities; namespace Umbraco.Tests.Services { @@ -61,6 +62,18 @@ namespace Umbraco.Tests.Services Assert.That(entities.Any(x => x.Trashed), Is.True); } + [Test] + public void EntityService_Can_Get_Child_Content_By_ParentId_And_UmbracoObjectType() + { + var service = ServiceContext.EntityService; + + var entities = service.GetChildren(-1, UmbracoObjectTypes.Document); + + Assert.That(entities.Any(), Is.True); + Assert.That(entities.Count(), Is.EqualTo(1)); + Assert.That(entities.Any(x => x.Trashed), Is.False); + } + [Test] public void EntityService_Throws_When_Getting_All_With_Invalid_Type() { @@ -105,5 +118,37 @@ namespace Umbraco.Tests.Services Assert.That(entities.Any(), Is.True); Assert.That(entities.Count(), Is.EqualTo(1)); } + + [Test] + public void EntityService_Can_Find_All_Media_By_UmbracoObjectTypes() + { + var service = ServiceContext.EntityService; + + var entities = service.GetAll(UmbracoObjectTypes.Media); + + Assert.That(entities.Any(), Is.True); + Assert.That(entities.Count(), Is.EqualTo(3)); + Assert.That(entities.Any(x => ((UmbracoEntity)x).UmbracoFile != string.Empty), Is.True); + } + + public override void CreateTestData() + { + base.CreateTestData(); + + //Create and Save folder-Media -> 1050 + var folderMediaType = ServiceContext.ContentTypeService.GetMediaType(1031); + var folder = MockedMedia.CreateMediaFolder(folderMediaType, -1); + ServiceContext.MediaService.Save(folder, 0); + + //Create and Save image-Media -> 1051 + var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032); + var image = MockedMedia.CreateMediaImage(imageMediaType, folder.Id); + ServiceContext.MediaService.Save(image, 0); + + //Create and Save file-Media -> 1052 + var fileMediaType = ServiceContext.ContentTypeService.GetMediaType(1033); + var file = MockedMedia.CreateMediaFile(fileMediaType, folder.Id); + ServiceContext.MediaService.Save(file, 0); + } } } \ No newline at end of file diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseMediaTree.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseMediaTree.cs index be85585f8e..98569162a3 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseMediaTree.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseMediaTree.cs @@ -1,26 +1,30 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Text; +using Umbraco.Core.Logging; +using Umbraco.Core.Models; using umbraco.BasePages; using umbraco.BusinessLogic; using umbraco.BusinessLogic.Actions; -using umbraco.cms.businesslogic.media; -using umbraco.cms.businesslogic.property; using umbraco.interfaces; using Umbraco.Core; +using Media = umbraco.cms.businesslogic.media.Media; +using Property = umbraco.cms.businesslogic.property.Property; namespace umbraco.cms.presentation.Trees { public abstract class BaseMediaTree : BaseTree { + private DisposableTimer _timer; + private User _user; + public BaseMediaTree(string application) : base(application) { } - private User m_user; - /// /// Returns the current User. This ensures that we don't instantiate a new User object /// each time. @@ -29,11 +33,10 @@ namespace umbraco.cms.presentation.Trees { get { - return (m_user == null ? (m_user = UmbracoEnsuredPage.CurrentUser) : m_user); + return (_user == null ? (_user = UmbracoEnsuredPage.CurrentUser) : _user); } } - public override void RenderJS(ref StringBuilder Javascript) { if (!string.IsNullOrEmpty(this.FunctionToCall)) @@ -53,8 +56,83 @@ function openMedia(id) { } } + //Updated Render method for improved performance, but currently not usable because of backwards compatibility + //with the OnBeforeTreeRender/OnAfterTreeRender events, which sends an array for legacy Media items. + /*public override void Render(ref XmlTree tree) + { + _timer = DisposableTimer.Start(x => LogHelper.Info("Media tree loaded" + " (took " + x + "ms)")); + + var service = base.Services.EntityService; + var entities = service.GetChildren(m_id, UmbracoObjectTypes.Media); + + var args = new TreeEventArgs(tree); + OnBeforeTreeRender(entities, args); + + foreach (UmbracoEntity entity in entities) + { + XmlTreeNode xNode = XmlTreeNode.Create(this); + xNode.NodeID = entity.Id.ToString(CultureInfo.InvariantCulture); + xNode.Text = entity.Name; + + xNode.HasChildren = entity.HasChildren; + xNode.Source = this.IsDialog ? GetTreeDialogUrl(entity.Id) : GetTreeServiceUrl(entity.Id); + + xNode.Icon = entity.ContentTypeIconUrl; + xNode.OpenIcon = entity.ContentTypeIconUrl; + + xNode.Menu = this.ShowContextMenu ? new List(new IAction[] { ActionRefresh.Instance }) : null; + + if (IsDialog == false) + { + xNode.Action = "javascript:openMedia(" + entity.Id + ");"; + } + else + { + if (this.DialogMode == TreeDialogModes.fulllink) + { + if (string.IsNullOrEmpty(entity.UmbracoFile) == false) + { + xNode.Action = "javascript:openMedia('" + entity.UmbracoFile + "');"; + } + else + { + if (string.Equals(entity.ContentTypeAlias, Constants.Conventions.MediaTypes.Folder, StringComparison.OrdinalIgnoreCase)) + { + xNode.Action = "javascript:jQuery('.umbTree #" + entity.Id.ToString(CultureInfo.InvariantCulture) + "').click();"; + } + else + { + xNode.Action = null; + xNode.Style.DimNode(); + } + } + } + else + { + xNode.Action = "javascript:openMedia('" + entity.Id.ToString(CultureInfo.InvariantCulture) + "');"; + } + } + + OnBeforeNodeRender(ref tree, ref xNode, EventArgs.Empty); + if (xNode != null) + { + tree.Add(xNode); + OnAfterNodeRender(ref tree, ref xNode, EventArgs.Empty); + } + } + + //stop the timer and log the output + _timer.Dispose(); + + OnAfterTreeRender(entities, args); + }*/ + public override void Render(ref XmlTree tree) { +#if Debug + _timer = DisposableTimer.Start(x => LogHelper.Info("Media tree loaded" + " (took " + x + "ms)")); +#endif + Media[] docs = new Media(m_id).Children; var args = new TreeEventArgs(tree); @@ -124,10 +202,13 @@ function openMedia(id) { OnAfterNodeRender(ref tree, ref xNode, EventArgs.Empty); } } +#if Debug + _timer.Dispose(); +#endif OnAfterTreeRender(docs, args); } - /// + /// /// Returns the value for a link in WYSIWYG mode, by default only media items that have a /// DataTypeUploadField are linkable, however, a custom tree can be created which overrides /// this method, or another GUID for a custom data type can be added to the LinkableMediaDataTypes diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadMedia.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadMedia.cs index 90135d9d15..80a1e4d307 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadMedia.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadMedia.cs @@ -1,28 +1,9 @@ using System; -using System.Collections; using System.Collections.Generic; -using System.Data; -using System.IO; -using System.Text; -using System.Web; -using System.Xml; -using System.Configuration; using umbraco.BasePages; -using umbraco.BusinessLogic; using umbraco.businesslogic; -using umbraco.cms.businesslogic; -using umbraco.cms.businesslogic.cache; -using umbraco.cms.businesslogic.contentitem; -using umbraco.cms.businesslogic.datatype; -using umbraco.cms.businesslogic.language; -using umbraco.cms.businesslogic.media; -using umbraco.cms.businesslogic.member; -using umbraco.cms.businesslogic.property; -using umbraco.cms.businesslogic.web; using umbraco.interfaces; -using umbraco.DataLayer; using umbraco.BusinessLogic.Actions; -using umbraco.BusinessLogic.Utils; using umbraco.cms.presentation.Trees; using Umbraco.Core; From 640be73a669f2106b0c58bfb4ab0957703608374 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Wed, 3 Apr 2013 07:03:57 -0200 Subject: [PATCH 15/16] A few refactoring bits for the FolderBrowserService. --- src/Umbraco.Core/Models/UmbracoEntity.cs | 19 ++++++++- .../Factories/UmbracoEntityFactory.cs | 3 +- .../Repositories/EntityRepository.cs | 7 +++- .../WebServices/FolderBrowserService.cs | 42 +++++++++---------- .../umbraco/Trees/BaseMediaTree.cs | 14 +++---- 5 files changed, 49 insertions(+), 36 deletions(-) diff --git a/src/Umbraco.Core/Models/UmbracoEntity.cs b/src/Umbraco.Core/Models/UmbracoEntity.cs index d87ec768f9..f3ab2b71e0 100644 --- a/src/Umbraco.Core/Models/UmbracoEntity.cs +++ b/src/Umbraco.Core/Models/UmbracoEntity.cs @@ -36,10 +36,12 @@ namespace Umbraco.Core.Models private static readonly PropertyInfo IsDraftSelector = ExpressionHelper.GetPropertyInfo(x => x.IsDraft); private static readonly PropertyInfo HasPendingChangesSelector = ExpressionHelper.GetPropertyInfo(x => x.HasPendingChanges); private static readonly PropertyInfo ContentTypeAliasSelector = ExpressionHelper.GetPropertyInfo(x => x.ContentTypeAlias); - private static readonly PropertyInfo ContentTypeIconUrlSelector = ExpressionHelper.GetPropertyInfo(x => x.ContentTypeIcon); + private static readonly PropertyInfo ContentTypeIconSelector = ExpressionHelper.GetPropertyInfo(x => x.ContentTypeIcon); + private static readonly PropertyInfo ContentTypeThumbnailSelector = ExpressionHelper.GetPropertyInfo(x => x.ContentTypeThumbnail); private static readonly PropertyInfo UmbracoFileSelector = ExpressionHelper.GetPropertyInfo(x => x.UmbracoFile); private static readonly PropertyInfo NodeObjectTypeIdSelector = ExpressionHelper.GetPropertyInfo(x => x.NodeObjectTypeId); private string _contentTypeIcon; + private string _contentTypeThumbnail; public UmbracoEntity() { @@ -215,7 +217,20 @@ namespace Umbraco.Core.Models { _contentTypeIcon = value; return _contentTypeIcon; - }, _contentTypeIcon, ContentTypeIconUrlSelector); + }, _contentTypeIcon, ContentTypeIconSelector); + } + } + + public string ContentTypeThumbnail + { + get { return _contentTypeThumbnail; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _contentTypeThumbnail = value; + return _contentTypeThumbnail; + }, _contentTypeThumbnail, ContentTypeThumbnailSelector); } } diff --git a/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs b/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs index e2e319829b..e26b43f5a6 100644 --- a/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs @@ -23,7 +23,8 @@ namespace Umbraco.Core.Persistence.Factories SortOrder = dto.SortOrder, HasChildren = dto.Children > 0, ContentTypeAlias = dto.Alias ?? string.Empty, - ContentTypeIcon = dto.IconUrl ?? string.Empty, + ContentTypeIcon = dto.Icon ?? string.Empty, + ContentTypeThumbnail = dto.Thumbnail ?? string.Empty, UmbracoFile = dto.UmbracoFile ?? string.Empty }; diff --git a/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs b/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs index 7fdec8702f..2a898006e4 100644 --- a/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs @@ -152,6 +152,7 @@ namespace Umbraco.Core.Persistence.Repositories columns.Add("latest.versionId as newestVersion"); columns.Add("contenttype.alias"); columns.Add("contenttype.icon"); + columns.Add("contenttype.thumbnail"); columns.Add("property.dataNvarchar as umbracoFile"); } @@ -226,6 +227,7 @@ namespace Umbraco.Core.Persistence.Repositories columns.Add("latest.versionId"); columns.Add("contenttype.alias"); columns.Add("contenttype.icon"); + columns.Add("contenttype.thumbnail"); columns.Add("property.dataNvarchar"); } @@ -267,7 +269,10 @@ namespace Umbraco.Core.Persistence.Repositories public string Alias { get; set; } [Column("icon")] - public string IconUrl { get; set; } + public string Icon { get; set; } + + [Column("thumbnail")] + public string Thumbnail { get; set; } [Column("umbracoFile")] public string UmbracoFile { get; set; } diff --git a/src/Umbraco.Web/WebServices/FolderBrowserService.cs b/src/Umbraco.Web/WebServices/FolderBrowserService.cs index 4a060f5c6b..63eb497e69 100644 --- a/src/Umbraco.Web/WebServices/FolderBrowserService.cs +++ b/src/Umbraco.Web/WebServices/FolderBrowserService.cs @@ -1,16 +1,14 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; -using System.Text; -using System.Web; using System.Web.Script.Serialization; using Umbraco.Core; +using Umbraco.Core.IO; +using Umbraco.Core.Models; using Umbraco.Web.Media.ThumbnailProviders; -using umbraco.BasePages; using umbraco.BusinessLogic; -using umbraco.IO; using umbraco.cms.businesslogic.Tags; -using umbraco.cms.businesslogic.media; using Umbraco.Web.BaseRest; namespace Umbraco.Web.WebServices @@ -23,7 +21,10 @@ namespace Umbraco.Web.WebServices [RestExtensionMethod(ReturnXml = false)] public static string GetChildren(int parentId) { - var parentMedia = new global::umbraco.cms.businesslogic.media.Media(parentId); + var service = ApplicationContext.Current.Services.EntityService; + var parentMedia = service.Get(parentId, UmbracoObjectTypes.Media); + var mediaPath = parentMedia == null ? parentId.ToString(CultureInfo.InvariantCulture) : parentMedia.Path; + var currentUser = User.GetCurrent(); var data = new List(); @@ -32,32 +33,27 @@ namespace Umbraco.Web.WebServices throw new UnauthorizedAccessException("You must be logged in to use this service"); // Check user is allowed to access selected media item - if(!("," + parentMedia.Path + ",").Contains("," + currentUser.StartMediaId + ",")) + if (!("," + mediaPath + ",").Contains("," + currentUser.StartMediaId + ",")) throw new UnauthorizedAccessException("You do not have access to this Media node"); // Get children and filter + var entities = service.GetChildren(parentId, UmbracoObjectTypes.Media); //TODO: Only fetch files, not containers - //TODO: Cache responses to speed up susequent searches - foreach (var child in parentMedia.Children) + foreach (UmbracoEntity entity in entities) { - var fileProp = child.getProperty(Constants.Conventions.Media.File) ?? - child.GenericProperties.FirstOrDefault(x => - x.PropertyType.DataTypeDefinition.DataType.Id == new Guid(Constants.PropertyEditors.UploadField)); - - var fileUrl = fileProp != null ? fileProp.Value.ToString() : ""; - var thumbUrl = ThumbnailProvidersResolver.Current.GetThumbnailUrl(fileUrl); + var thumbUrl = ThumbnailProvidersResolver.Current.GetThumbnailUrl(entity.UmbracoFile); var item = new { - Id = child.Id, - Path = child.Path, - Name = child.Text, - Tags = string.Join(",", Tag.GetTags(child.Id).Select(x => x.TagCaption)), - MediaTypeAlias = child.ContentType.Alias, - EditUrl = string.Format("editMedia.aspx?id={0}", child.Id), - FileUrl = fileUrl, + Id = entity.Id, + Path = entity.Path, + Name = entity.Name, + Tags = string.Join(",", Tag.GetTags(entity.Id).Select(x => x.TagCaption)), + MediaTypeAlias = entity.ContentTypeAlias, + EditUrl = string.Format("editMedia.aspx?id={0}", entity.Id), + FileUrl = entity.UmbracoFile, ThumbnailUrl = !string.IsNullOrEmpty(thumbUrl) ? thumbUrl - : IOHelper.ResolveUrl(SystemDirectories.Umbraco + "/images/thumbnails/" + child.ContentType.Thumbnail) + : IOHelper.ResolveUrl(SystemDirectories.Umbraco + "/images/thumbnails/" + entity.ContentTypeThumbnail) }; data.Add(item); diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseMediaTree.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseMediaTree.cs index 98569162a3..ab25a34e13 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseMediaTree.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseMediaTree.cs @@ -60,7 +60,7 @@ function openMedia(id) { //with the OnBeforeTreeRender/OnAfterTreeRender events, which sends an array for legacy Media items. /*public override void Render(ref XmlTree tree) { - _timer = DisposableTimer.Start(x => LogHelper.Info("Media tree loaded" + " (took " + x + "ms)")); + _timer = DisposableTimer.Start(x => LogHelper.Debug("Media tree loaded" + " (took " + x + "ms)")); var service = base.Services.EntityService; var entities = service.GetChildren(m_id, UmbracoObjectTypes.Media); @@ -77,8 +77,8 @@ function openMedia(id) { xNode.HasChildren = entity.HasChildren; xNode.Source = this.IsDialog ? GetTreeDialogUrl(entity.Id) : GetTreeServiceUrl(entity.Id); - xNode.Icon = entity.ContentTypeIconUrl; - xNode.OpenIcon = entity.ContentTypeIconUrl; + xNode.Icon = entity.ContentTypeIcon; + xNode.OpenIcon = entity.ContentTypeIcon; xNode.Menu = this.ShowContextMenu ? new List(new IAction[] { ActionRefresh.Instance }) : null; @@ -129,9 +129,7 @@ function openMedia(id) { public override void Render(ref XmlTree tree) { -#if Debug - _timer = DisposableTimer.Start(x => LogHelper.Info("Media tree loaded" + " (took " + x + "ms)")); -#endif + //_timer = DisposableTimer.Start(x => LogHelper.Debug("Media tree loaded" + " (took " + x + "ms)")); Media[] docs = new Media(m_id).Children; @@ -202,9 +200,7 @@ function openMedia(id) { OnAfterNodeRender(ref tree, ref xNode, EventArgs.Empty); } } -#if Debug - _timer.Dispose(); -#endif + //_timer.Dispose(); OnAfterTreeRender(docs, args); } From b93ea7c69bff855d01648879c5e2c02b7db1305f Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 3 Apr 2013 08:40:09 -0200 Subject: [PATCH 16/16] U4-2033 - fix the tests, now we're returning lower case --- .../CoreStrings/LegacyShortStringHelperTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Tests/CoreStrings/LegacyShortStringHelperTests.cs b/src/Umbraco.Tests/CoreStrings/LegacyShortStringHelperTests.cs index ec19f59176..8df226e853 100644 --- a/src/Umbraco.Tests/CoreStrings/LegacyShortStringHelperTests.cs +++ b/src/Umbraco.Tests/CoreStrings/LegacyShortStringHelperTests.cs @@ -81,10 +81,10 @@ namespace Umbraco.Tests.CoreStrings } #region Cases - [TestCase("Home Page", "Home-Page")] - [TestCase("Shannon's Home Page!", "Shannons-Home-Page!")] - [TestCase("#Someones's Twitter $h1z%n", "Someoness-Twitter-$h1zn")] - [TestCase("Räksmörgås", "Raeksmoergaas")] + [TestCase("Home Page", "home-page")] + [TestCase("Shannon's Home Page!", "shannons-home-page!")] + [TestCase("#Someones's Twitter $h1z%n", "someoness-twitter-$h1zn")] + [TestCase("Räksmörgås", "raeksmoergaas")] [TestCase("'em guys-over there, are#goin' a \"little\"bit crazy eh!! :)", "em-guys-over-there,-aregoin-a-littlebit-crazy-eh!!-)")] [TestCase("汉#字*/漢?字", "汉字star漢字")] [TestCase("Réalösk fix bran#lo'sk", "realosk-fix-bran-lo-sk", IgnoreReason = "cannot handle it")]