PageRenderTime 61ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/CompositeC1/Composite.Workflows/Plugins/Elements/ElementProviders/PageTemplateElementProvider/EditPageTemplateWorkflow.cs

#
C# | 224 lines | 166 code | 38 blank | 20 comment | 26 complexity | c5f5648d7d9804f7106a3a02c04b2c8b MD5 | raw file
Possible License(s): LGPL-2.1
  1. /*
  2. * The contents of this web application are subject to the Mozilla Public License Version
  3. * 1.1 (the "License"); you may not use this web application except in compliance with
  4. * the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/.
  5. *
  6. * Software distributed under the License is distributed on an "AS IS" basis,
  7. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  8. * for the specific language governing rights and limitations under the License.
  9. *
  10. * The Original Code is owned by and the Initial Developer of the Original Code is
  11. * Composite A/S (Danish business reg.no. 21744409). All Rights Reserved
  12. *
  13. * Section 11 of the License is EXPRESSLY amended to include a provision stating
  14. * that any dispute, including but not limited to disputes related to the enforcement
  15. * of the License, to which Composite A/S as owner of the Original Code, as Initial
  16. * Developer or in any other role, becomes a part to shall be governed by Danish law
  17. * and be initiated before the Copenhagen City Court ("K???benhavns Byret")
  18. */
  19. using System;
  20. using System.Collections.Generic;
  21. using System.IO;
  22. using System.Linq;
  23. using System.Workflow.Runtime;
  24. using System.Xml.Linq;
  25. using Composite.C1Console.Actions;
  26. using Composite.C1Console.Events;
  27. using Composite.C1Console.Workflow;
  28. using Composite.Core.Extensions;
  29. using Composite.Core.IO;
  30. using Composite.Core.ResourceSystem;
  31. using Composite.Core.Xml;
  32. using Composite.Data;
  33. using Composite.Data.Plugins.DataProvider.Streams;
  34. using Composite.Data.Types;
  35. using Composite.Functions;
  36. namespace Composite.Plugins.Elements.ElementProviders.PageTemplateElementProvider
  37. {
  38. [EntityTokenLock()]
  39. [AllowPersistingWorkflow(WorkflowPersistingType.Idle)]
  40. public sealed partial class EditPageTemplateWorkflow : Composite.C1Console.Workflow.Activities.FormsWorkflow
  41. {
  42. public EditPageTemplateWorkflow()
  43. {
  44. InitializeComponent();
  45. }
  46. private void initializeCodeActivity_ExecuteCode(object sender, EventArgs e)
  47. {
  48. DataEntityToken dataEntityToken = (DataEntityToken)this.EntityToken;
  49. this.Bindings.Add("PageTemplate", dataEntityToken.Data);
  50. this.Bindings.Add("OldTitle", ((IPageTemplate)dataEntityToken.Data).Title);
  51. string templatePath = ((IPageTemplate)dataEntityToken.Data).PageTemplateFilePath;
  52. IPageTemplateFile file = IFileServices.TryGetFile<IPageTemplateFile>(templatePath);
  53. this.Bindings.Add("PageTemplateMarkup", file.ReadAllText());
  54. }
  55. private void codeActivity1_ExecuteCode(object sender, EventArgs e)
  56. {
  57. IPageTemplate pageTemplate = this.GetBinding<IPageTemplate>("PageTemplate");
  58. string pageTemplateMarkup = this.GetBinding<string>("PageTemplateMarkup");
  59. bool xhtmlParseable = true;
  60. string parseError = null;
  61. try
  62. {
  63. XDocument parsedElement = XDocument.Parse(pageTemplateMarkup);
  64. ValidatePageTemplate(parsedElement);
  65. }
  66. catch (Exception ex)
  67. {
  68. xhtmlParseable = false;
  69. parseError = ex.Message;
  70. }
  71. if (!xhtmlParseable)
  72. {
  73. FlowControllerServicesContainer serviceContainer = WorkflowFacade.GetFlowControllerServicesContainer(WorkflowEnvironment.WorkflowInstanceId);
  74. var consoleMessageService = serviceContainer.GetService<IManagementConsoleMessageService>();
  75. consoleMessageService.ShowMessage(
  76. DialogType.Error,
  77. GetString("EditPageTemplateWorkflow.InvalidXmlTitle"),
  78. GetString("EditPageTemplateWorkflow.InvalidXmlMessage").FormatWith(parseError));
  79. return;
  80. }
  81. // Renaming related file if necessary
  82. string fileName = pageTemplate.Title + ".xml";
  83. if (Path.GetFileName(pageTemplate.PageTemplateFilePath) != fileName)
  84. {
  85. IPageTemplateFile file = IFileServices.GetFile<IPageTemplateFile>(pageTemplate.PageTemplateFilePath);
  86. string systemPath = (file as FileSystemFileBase).SystemPath;
  87. string newSystemPath = Path.Combine(Path.GetDirectoryName(systemPath), fileName);
  88. if (string.Compare(systemPath, newSystemPath, true) != 0 && C1File.Exists(newSystemPath))
  89. {
  90. FlowControllerServicesContainer serviceContainer = WorkflowFacade.GetFlowControllerServicesContainer(WorkflowEnvironment.WorkflowInstanceId);
  91. var consoleMessageService = serviceContainer.GetService<IManagementConsoleMessageService>();
  92. consoleMessageService.ShowMessage(
  93. DialogType.Error,
  94. GetString("EditPageTemplateWorkflow.InvalidXmlTitle"),
  95. GetString("EditPageTemplateWorkflow.CannotRenameFileExists").FormatWith(newSystemPath));
  96. return;
  97. }
  98. C1File.Move(systemPath, newSystemPath);
  99. string newRelativePath = Path.Combine(Path.GetDirectoryName(pageTemplate.PageTemplateFilePath), fileName);
  100. pageTemplate.PageTemplateFilePath = newRelativePath;
  101. }
  102. IPageTemplateFile templateFile = IFileServices.GetFile<IPageTemplateFile>(pageTemplate.PageTemplateFilePath);
  103. templateFile.SetNewContent(pageTemplateMarkup);
  104. DataFacade.Update(templateFile);
  105. DataFacade.Update(pageTemplate);
  106. UpdateTreeRefresher updateTreeRefresher = this.CreateUpdateTreeRefresher(this.EntityToken);
  107. updateTreeRefresher.PostRefreshMesseges(pageTemplate.GetDataEntityToken());
  108. SetSaveStatus(true);
  109. }
  110. private static string GetString(string key)
  111. {
  112. return StringResourceSystemFacade.GetString("Composite.Plugins.PageTemplateElementProvider", key);
  113. }
  114. private void ValidatePageTemplate(XDocument xDocument)
  115. {
  116. // check unique id's
  117. List<XAttribute> valueOrderedIdAttributes = xDocument.Descendants().Attributes("id").OrderBy(f => f.Value).ToList();
  118. XElement rootElement = xDocument.Root;
  119. if (rootElement.Name.LocalName.ToLower() == "html")
  120. {
  121. if (rootElement.Name.Namespace != Namespaces.Xhtml)
  122. {
  123. throw new InvalidOperationException(string.Format("Root element 'html' must belong to the namespace '{0}'. Change the \"<html>\" tag to \"<html xmlns='{0}'>\"", Namespaces.Xhtml));
  124. }
  125. if (rootElement.Name.LocalName != rootElement.Name.LocalName.ToLower())
  126. {
  127. throw new InvalidOperationException("Root element 'html' must be written in lower case.");
  128. }
  129. }
  130. for (int i = 0; i < valueOrderedIdAttributes.Count - 1; i++)
  131. {
  132. if (valueOrderedIdAttributes[i].Value == valueOrderedIdAttributes[i + 1].Value)
  133. {
  134. throw new InvalidOperationException(string.Format("The id '{0}' is used on multiple elements ('{1}' and '{2}'). Element id values must be unique.", valueOrderedIdAttributes[i].Value, valueOrderedIdAttributes[i].Parent.Name.LocalName, valueOrderedIdAttributes[i + 1].Parent.Name.LocalName));
  135. }
  136. }
  137. foreach (XElement element in xDocument.Descendants().Where(f => f.Name.Namespace == Namespaces.AspNetControls))
  138. {
  139. switch (element.Name.LocalName)
  140. {
  141. case "form":
  142. case "placeholder":
  143. break;
  144. default:
  145. throw new InvalidOperationException(string.Format("Unknown element '{0}' in namespace '{1}'.", element.Name.LocalName, Namespaces.AspNetControls));
  146. }
  147. }
  148. foreach (XElement element in xDocument.Descendants().Where(f => f.Name.Namespace == Namespaces.Rendering10))
  149. {
  150. switch (element.Name.LocalName)
  151. {
  152. case "page.title":
  153. case "page.description":
  154. case "page.metatag.description":
  155. case "placeholder":
  156. break;
  157. default:
  158. throw new InvalidOperationException(string.Format("Unknown element '{0}' in namespace '{1}'.", element.Name.LocalName, Namespaces.Rendering10));
  159. }
  160. }
  161. if (1 < xDocument.Descendants(Namespaces.Rendering10 + "placeholder").Attributes("default").Where(f => f.Value == "true").Count())
  162. {
  163. throw new InvalidOperationException(string.Format("Multiple '{0}' elements are set to be default. Only one element may be default.", "placeholder"));
  164. }
  165. foreach (XElement element in xDocument.Descendants(Namespaces.Function10 + "function"))
  166. {
  167. FunctionFacade.BuildTree(element);
  168. }
  169. }
  170. private void IsTitleUsed(object sender, System.Workflow.Activities.ConditionalEventArgs e)
  171. {
  172. IPageTemplate newPageTemplate = this.GetBinding<IPageTemplate>("PageTemplate");
  173. if (this.GetBinding<string>("OldTitle") == newPageTemplate.Title)
  174. {
  175. e.Result = false;
  176. return;
  177. }
  178. e.Result = DataFacade.GetData<IPageTemplate>(f => f.Title == newPageTemplate.Title
  179. && f.Id != newPageTemplate.Id).Any();
  180. }
  181. private void ShowMessageCodeActivity_ExecuteCode(object sender, EventArgs e)
  182. {
  183. ShowFieldMessage("PageTemplate.Title", GetString("EditPageTemplateWorkflow.TitleInUseTitle"));
  184. }
  185. }
  186. }