diff --git a/.gitignore b/.gitignore index c4bc566998..2b1fe2df69 100644 --- a/.gitignore +++ b/.gitignore @@ -27,4 +27,7 @@ /Bin/Composite.dll /Bin/Composite.Workflows.dll -/Packages/ \ No newline at end of file +/Packages/ + +selenium-debug.log +/Website/test/e2e/reports/ diff --git a/Composite.Workflows/C1Console/Scheduling/PagePublishSchedulerWorkflow.cs b/Composite.Workflows/C1Console/Scheduling/PagePublishSchedulerWorkflow.cs index 8149f9df3b..7253265625 100644 --- a/Composite.Workflows/C1Console/Scheduling/PagePublishSchedulerWorkflow.cs +++ b/Composite.Workflows/C1Console/Scheduling/PagePublishSchedulerWorkflow.cs @@ -1,22 +1,15 @@ using System; using System.ComponentModel; using System.Globalization; -using System.Linq; - -using Composite.Core; using Composite.Data; -using Composite.Data.ProcessControlled; -using Composite.Data.ProcessControlled.ProcessControllers.GenericPublishProcessController; using Composite.Data.PublishScheduling; -using Composite.Data.Transactions; using Composite.Data.Types; namespace Composite.C1Console.Scheduling { + [Obsolete] public sealed class PagePublishSchedulerWorkflow : BaseSchedulerWorkflow { - private static readonly string LogTitle = typeof(PagePublishSchedulerWorkflow).Name; - [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Guid PageId { get; set; } @@ -24,36 +17,10 @@ protected override void Execute() { using (new DataScope(DataScopeIdentifier.Administrated, CultureInfo.CreateSpecificCulture(LocaleName))) { - IPage page; - - using (var transaction = TransactionsFacade.CreateNewScope()) - { - var pagePublishSchedule = PublishScheduleHelper.GetPublishSchedule(typeof(IPage), PageId.ToString(), LocaleName); - DataFacade.Delete(pagePublishSchedule); - - page = DataFacade.GetData(p => p.Id == PageId).FirstOrDefault(); - - - Verify.IsNotNull(page, "The page with the id {0} does not exist", PageId); - - var transitions = ProcessControllerFacade.GetValidTransitions(page).Keys; - if (transitions.Contains(GenericPublishProcessController.Published)) - { - page.PublicationStatus = GenericPublishProcessController.Published; - - DataFacade.Update(page); - - Log.LogVerbose(LogTitle, "Scheduled publishing of page with title '{0}' is complete", page.Title); - } - else - { - Log.LogWarning(LogTitle, "Scheduled publishing of page with title '{0}' could not be done because the page is not in a publisheble state", page.Title); - } - - transaction.Complete(); - } + var pagePublishSchedule = PublishScheduleHelper.GetPublishSchedule(typeof(IPage), PageId.ToString(), LocaleName); + DataFacade.Delete(pagePublishSchedule); - PublishControlledHelper.ReloadPageElementInConsole(page); + // NOTE: publication logic removed } } } diff --git a/Composite.Workflows/C1Console/Scheduling/PageUnpublishSchedulerWorkflow.cs b/Composite.Workflows/C1Console/Scheduling/PageUnpublishSchedulerWorkflow.cs index db19d1c4e5..a10bd07e24 100644 --- a/Composite.Workflows/C1Console/Scheduling/PageUnpublishSchedulerWorkflow.cs +++ b/Composite.Workflows/C1Console/Scheduling/PageUnpublishSchedulerWorkflow.cs @@ -1,23 +1,15 @@ using System; using System.ComponentModel; using System.Globalization; -using System.Linq; - -using Composite.Core; -using Composite.Core.Linq; using Composite.Data; -using Composite.Data.ProcessControlled; -using Composite.Data.ProcessControlled.ProcessControllers.GenericPublishProcessController; using Composite.Data.PublishScheduling; -using Composite.Data.Transactions; using Composite.Data.Types; namespace Composite.C1Console.Scheduling { + [Obsolete] public sealed class PageUnpublishSchedulerWorkflow : BaseSchedulerWorkflow { - private static readonly string LogTitle = typeof(PageUnpublishSchedulerWorkflow).Name; - [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Guid PageId { get; set; } @@ -25,54 +17,12 @@ protected override void Execute() { using (new DataScope(DataScopeIdentifier.Administrated, CultureInfo.CreateSpecificCulture(LocaleName))) { - IPage page; - - using (var transaction = TransactionsFacade.CreateNewScope()) - { - var pageUnpublishSchedule = PublishScheduleHelper.GetUnpublishSchedule(typeof (IPage), PageId.ToString(), LocaleName); - Verify.IsNotNull(pageUnpublishSchedule, "Missing an unpublish page schedule record."); - - DataFacade.Delete(pageUnpublishSchedule); - - var deletePublished = false; - - page = DataFacade.GetData(p => p.Id == PageId).FirstOrDefault(); - - var transitions = ProcessControllerFacade.GetValidTransitions(page).Keys; - if (transitions.Contains(GenericPublishProcessController.Draft)) - { - page.PublicationStatus = GenericPublishProcessController.Draft; - - DataFacade.Update(page); - - deletePublished = true; - } - else - { - Log.LogWarning(LogTitle, "Scheduled unpublishing of page with title '{0}' could not be done because the page is not in a unpublisheble state", page.Title); - } - - if (deletePublished) - { - using (new DataScope(DataScopeIdentifier.Public)) - { - var deletePage = DataFacade.GetData(p => p.Id == PageId).FirstOrDefault(); - if (deletePage != null) - { - var metaDataSet = deletePage.GetMetaData(DataScopeIdentifier.Public).Evaluate(); - - DataFacade.Delete(deletePage, CascadeDeleteType.Disable); - DataFacade.Delete(metaDataSet, CascadeDeleteType.Disable); - - Log.LogVerbose(LogTitle, "Scheduled unpublishing of page with title '{0}' is complete", deletePage.Title); - } - } - } + var pageUnpublishSchedule = PublishScheduleHelper.GetUnpublishSchedule(typeof (IPage), PageId.ToString(), LocaleName); + Verify.IsNotNull(pageUnpublishSchedule, "Missing an unpublish page schedule record."); - transaction.Complete(); - } + DataFacade.Delete(pageUnpublishSchedule); - PublishControlledHelper.ReloadPageElementInConsole(page); + // NOTE: Unpublication logic removed } } } diff --git a/Composite.Workflows/C1Console/Scheduling/PublishControlledHelper.cs b/Composite.Workflows/C1Console/Scheduling/PublishControlledHelper.cs index c1fe8064ca..af424ddb08 100644 --- a/Composite.Workflows/C1Console/Scheduling/PublishControlledHelper.cs +++ b/Composite.Workflows/C1Console/Scheduling/PublishControlledHelper.cs @@ -73,53 +73,6 @@ public static void HandlePublishUnpublishWorkflows(IData selectedData, string cu } } - public static void HandlePublishUnpublishWorkflows(IPage selectedPage, string cultureName, DateTime? publishDate, DateTime? unpublishDate, ref WorkflowInstance publishWorkflowInstance, ref WorkflowInstance unpublishWorkflowInstance) - { - var existingPublishSchedule = PublishScheduleHelper.GetPublishSchedule(typeof(IPage), selectedPage.Id.ToString(), cultureName); - if (existingPublishSchedule != null) - { - WorkflowFacade.AbortWorkflow(existingPublishSchedule.WorkflowInstanceId); - - DataFacade.Delete(existingPublishSchedule); - } - - if (publishDate != null) - { - publishWorkflowInstance = WorkflowFacade.CreateNewWorkflow( - typeof(PagePublishSchedulerWorkflow), - new Dictionary - { - { "Date", publishDate }, - { "PageId", selectedPage.Id }, - { "LocaleName", cultureName } - }); - - PublishScheduleHelper.CreatePublishSchedule(typeof(IPage), selectedPage.Id.ToString(), cultureName, publishDate.Value, publishWorkflowInstance); - } - - var existingUnpublishSchedule = PublishScheduleHelper.GetUnpublishSchedule(typeof(IPage), selectedPage.Id.ToString(), cultureName); - if (existingUnpublishSchedule != null) - { - WorkflowFacade.AbortWorkflow(existingUnpublishSchedule.WorkflowInstanceId); - - DataFacade.Delete(existingUnpublishSchedule); - } - - if (unpublishDate != null) - { - unpublishWorkflowInstance = WorkflowFacade.CreateNewWorkflow( - typeof(PageUnpublishSchedulerWorkflow), - new Dictionary - { - { "Date", unpublishDate }, - { "PageId", selectedPage.Id }, - { "LocaleName", cultureName } - }); - - PublishScheduleHelper.CreateUnpublishSchedule(typeof(IPage), selectedPage.Id.ToString(), cultureName, unpublishDate.Value, unpublishWorkflowInstance); - } - } - public static void ReloadPageElementInConsole(IPage page) { var parentPageId = PageManager.GetParentId(page.Id); diff --git a/Composite.Workflows/Composite.Workflows.csproj b/Composite.Workflows/Composite.Workflows.csproj index c61235d38a..4dd05d28d0 100644 --- a/Composite.Workflows/Composite.Workflows.csproj +++ b/Composite.Workflows/Composite.Workflows.csproj @@ -448,18 +448,6 @@ LocalizePageWorkflow.cs - - Component - - - PagePublishSchedulerWorkflow.cs - - - Component - - - PageUnpublishSchedulerWorkflow.cs - Component @@ -1109,12 +1097,6 @@ LocalizePageWorkflow.cs - - PagePublishSchedulerWorkflow.cs - - - PageUnpublishSchedulerWorkflow.cs - UndoUnpublishedChangesWorkflow.cs diff --git a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/DeletePageWorkflow.Designer.cs b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/DeletePageWorkflow.Designer.cs index 532b62f181..66d56ee594 100644 --- a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/DeletePageWorkflow.Designer.cs +++ b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/DeletePageWorkflow.Designer.cs @@ -18,21 +18,44 @@ private void InitializeComponent() System.Workflow.Activities.CodeCondition codecondition1 = new System.Workflow.Activities.CodeCondition(); System.Workflow.Activities.CodeCondition codecondition2 = new System.Workflow.Activities.CodeCondition(); System.Workflow.Activities.CodeCondition codecondition3 = new System.Workflow.Activities.CodeCondition(); - this.setStateActivity8 = new System.Workflow.Activities.SetStateActivity(); - this.setStateActivity7 = new System.Workflow.Activities.SetStateActivity(); - this.branchNoSubpages = new System.Workflow.Activities.IfElseBranchActivity(); - this.branchHasSubpages = new System.Workflow.Activities.IfElseBranchActivity(); - this.setStateActivity5 = new System.Workflow.Activities.SetStateActivity(); - this.confirmDialogFormActivity1 = new Composite.C1Console.Workflow.Activities.ConfirmDialogFormActivity(); - this.codeActivity1 = new System.Workflow.Activities.CodeActivity(); - this.testHasSubpages = new System.Workflow.Activities.IfElseActivity(); + System.Workflow.Activities.CodeCondition codecondition4 = new System.Workflow.Activities.CodeCondition(); + System.Workflow.Activities.CodeCondition codecondition5 = new System.Workflow.Activities.CodeCondition(); + System.Workflow.Activities.CodeCondition codecondition6 = new System.Workflow.Activities.CodeCondition(); + this.setStateActivity15 = new System.Workflow.Activities.SetStateActivity(); this.caCheckChildren = new System.Workflow.Activities.CodeActivity(); this.setStateActivity6 = new System.Workflow.Activities.SetStateActivity(); this.initializeCodeActivity_ShowError_InstanceCompositions = new System.Workflow.Activities.CodeActivity(); - this.branchRelatedDataDoesntExist = new System.Workflow.Activities.IfElseBranchActivity(); - this.branchRelatedDataExist = new System.Workflow.Activities.IfElseBranchActivity(); + this.setStateActivity19 = new System.Workflow.Activities.SetStateActivity(); + this.setStateActivity10 = new System.Workflow.Activities.SetStateActivity(); + this.setStateActivity16 = new System.Workflow.Activities.SetStateActivity(); + this.confirmDialogFormActivity2 = new Composite.C1Console.Workflow.Activities.ConfirmDialogFormActivity(); + this.codeActivity_SetupDeleteMultipleVersionsForm = new System.Workflow.Activities.CodeActivity(); + this.setStateActivity5 = new System.Workflow.Activities.SetStateActivity(); + this.confirmDialogFormActivity1 = new Composite.C1Console.Workflow.Activities.ConfirmDialogFormActivity(); + this.wizzardFormActivity2 = new Composite.C1Console.Workflow.Activities.ConfirmDialogFormActivity(); + this.setStateActivity7 = new System.Workflow.Activities.SetStateActivity(); + this.setStateActivity17 = new System.Workflow.Activities.SetStateActivity(); + this.wizzardFormActivity1 = new Composite.C1Console.Workflow.Activities.ConfirmDialogFormActivity(); this.branchNoCompositions = new System.Workflow.Activities.IfElseBranchActivity(); this.branchHasCompositions = new System.Workflow.Activities.IfElseBranchActivity(); + this.ifElseBranchActivity_DeleteCurrentVersion = new System.Workflow.Activities.IfElseBranchActivity(); + this.ifElseBranchActivity_DeleteAllVersions = new System.Workflow.Activities.IfElseBranchActivity(); + this.branch_HasSingleVersion = new System.Workflow.Activities.IfElseBranchActivity(); + this.branch_HasMultipleVersions = new System.Workflow.Activities.IfElseBranchActivity(); + this.branchRelatedDataDoesntExist = new System.Workflow.Activities.IfElseBranchActivity(); + this.branchRelatedDataExist = new System.Workflow.Activities.IfElseBranchActivity(); + this.branch_deletionNotConfirmed = new System.Workflow.Activities.IfElseBranchActivity(); + this.branch_DeletionConfirmed = new System.Workflow.Activities.IfElseBranchActivity(); + this.branch_NoSubpages = new System.Workflow.Activities.IfElseBranchActivity(); + this.branch_HasSubpages = new System.Workflow.Activities.IfElseBranchActivity(); + this.setStateActivity18 = new System.Workflow.Activities.SetStateActivity(); + this.codeActivity_DeleteCurrentVersion = new System.Workflow.Activities.CodeActivity(); + this.ifElse_HasInstanceCompositions = new System.Workflow.Activities.IfElseActivity(); + this.setStateActivity14 = new System.Workflow.Activities.SetStateActivity(); + this.cancelHandleExternalEventActivity5 = new Composite.C1Console.Workflow.Activities.CancelHandleExternalEventActivity(); + this.ifElseActivity_DeleteAllVersions = new System.Workflow.Activities.IfElseActivity(); + this.finishHandleExternalEventActivity4 = new Composite.C1Console.Workflow.Activities.FinishHandleExternalEventActivity(); + this.ifElse_HasMultipleVersions = new System.Workflow.Activities.IfElseActivity(); this.setStateActivity12 = new System.Workflow.Activities.SetStateActivity(); this.finishHandleExternalEventActivity1 = new Composite.C1Console.Workflow.Activities.FinishHandleExternalEventActivity(); this.setStateActivity13 = new System.Workflow.Activities.SetStateActivity(); @@ -42,16 +65,22 @@ private void InitializeComponent() this.cancelHandleExternalEventActivity3 = new Composite.C1Console.Workflow.Activities.CancelHandleExternalEventActivity(); this.setStateActivity2 = new System.Workflow.Activities.SetStateActivity(); this.finishHandleExternalEventActivity2 = new Composite.C1Console.Workflow.Activities.FinishHandleExternalEventActivity(); - this.wizzardFormActivity2 = new Composite.C1Console.Workflow.Activities.ConfirmDialogFormActivity(); + this.ifElse_DeletionAlreadyConfirmed = new System.Workflow.Activities.IfElseActivity(); this.setStateActivity3 = new System.Workflow.Activities.SetStateActivity(); this.closeCurrentViewActivity1 = new Composite.C1Console.Workflow.Activities.CloseCurrentViewActivity(); this.codeActivity2 = new System.Workflow.Activities.CodeActivity(); this.setStateActivity9 = new System.Workflow.Activities.SetStateActivity(); this.cancelHandleExternalEventActivity4 = new Composite.C1Console.Workflow.Activities.CancelHandleExternalEventActivity(); this.setStateActivity1 = new System.Workflow.Activities.SetStateActivity(); + this.codeActivity_DeletingChildrenConfirmed = new System.Workflow.Activities.CodeActivity(); this.finishHandleExternalEventActivity3 = new Composite.C1Console.Workflow.Activities.FinishHandleExternalEventActivity(); - this.wizzardFormActivity1 = new Composite.C1Console.Workflow.Activities.ConfirmDialogFormActivity(); - this.ifElse_HasInstanceCompositions = new System.Workflow.Activities.IfElseActivity(); + this.ifElse_HasSubpages = new System.Workflow.Activities.IfElseActivity(); + this.setStateActivity8 = new System.Workflow.Activities.SetStateActivity(); + this.stateInitializationActivity4 = new System.Workflow.Activities.StateInitializationActivity(); + this.initializeInitializationActivity = new System.Workflow.Activities.StateInitializationActivity(); + this.versions_eventDrivenActivity_Cancel = new System.Workflow.Activities.EventDrivenActivity(); + this.versions_eventDrivenActivity_Ok = new System.Workflow.Activities.EventDrivenActivity(); + this.stateInitializationActivity2 = new System.Workflow.Activities.StateInitializationActivity(); this.eventDrivenActivity_Finish = new System.Workflow.Activities.EventDrivenActivity(); this.eventDrivenActivity_Cancel = new System.Workflow.Activities.EventDrivenActivity(); this.stateInitializationActivity1 = new System.Workflow.Activities.StateInitializationActivity(); @@ -64,7 +93,10 @@ private void InitializeComponent() this.step1EventDrivenActivity_Cancel = new System.Workflow.Activities.EventDrivenActivity(); this.step1EventDrivenActivity_Finish = new System.Workflow.Activities.EventDrivenActivity(); this.step1InitializationActivity = new System.Workflow.Activities.StateInitializationActivity(); - this.initializeInitializationActivity = new System.Workflow.Activities.StateInitializationActivity(); + this.stateInitializationActivity3 = new System.Workflow.Activities.StateInitializationActivity(); + this.deleteCurrentVersionStateActivity = new System.Workflow.Activities.StateActivity(); + this.checkForCompositionsStateActivity = new System.Workflow.Activities.StateActivity(); + this.confirmDeletingAllVersionsStateActivity = new System.Workflow.Activities.StateActivity(); this.confDeletingReferencedDataStateActivity = new System.Workflow.Activities.StateActivity(); this.confirmationStateActivity = new System.Workflow.Activities.StateActivity(); this.eventDrivenActivity_GlobalCancel = new System.Workflow.Activities.EventDrivenActivity(); @@ -73,27 +105,52 @@ private void InitializeComponent() this.finalStateActivity = new System.Workflow.Activities.StateActivity(); this.initializeStateActivity = new System.Workflow.Activities.StateActivity(); // - // setStateActivity8 + // setStateActivity15 // - this.setStateActivity8.Name = "setStateActivity8"; - this.setStateActivity8.TargetStateName = "confDeletingReferencedDataStateActivity"; + this.setStateActivity15.Name = "setStateActivity15"; + this.setStateActivity15.TargetStateName = "confirmDeletingChildrenStateActivity"; // - // setStateActivity7 + // caCheckChildren // - this.setStateActivity7.Name = "setStateActivity7"; - this.setStateActivity7.TargetStateName = "confirmDeletingChildrenStateActivity"; + this.caCheckChildren.Description = "Checking page children"; + this.caCheckChildren.Name = "caCheckChildren"; + this.caCheckChildren.ExecuteCode += new System.EventHandler(this.codeActivity1_ExecuteCode); // - // branchNoSubpages + // setStateActivity6 // - this.branchNoSubpages.Activities.Add(this.setStateActivity8); - this.branchNoSubpages.Name = "branchNoSubpages"; + this.setStateActivity6.Name = "setStateActivity6"; + this.setStateActivity6.TargetStateName = "finalStateActivity"; // - // branchHasSubpages + // initializeCodeActivity_ShowError_InstanceCompositions // - this.branchHasSubpages.Activities.Add(this.setStateActivity7); - codecondition1.Condition += new System.EventHandler(this.HasSubpages); - this.branchHasSubpages.Condition = codecondition1; - this.branchHasSubpages.Name = "branchHasSubpages"; + this.initializeCodeActivity_ShowError_InstanceCompositions.Name = "initializeCodeActivity_ShowError_InstanceCompositions"; + this.initializeCodeActivity_ShowError_InstanceCompositions.ExecuteCode += new System.EventHandler(this.initializeCodeActivity_ShowError_InstanceCompositions_ExecuteCode); + // + // setStateActivity19 + // + this.setStateActivity19.Name = "setStateActivity19"; + this.setStateActivity19.TargetStateName = "deleteCurrentVersionStateActivity"; + // + // setStateActivity10 + // + this.setStateActivity10.Name = "setStateActivity10"; + this.setStateActivity10.TargetStateName = "checkForCompositionsStateActivity"; + // + // setStateActivity16 + // + this.setStateActivity16.Name = "setStateActivity16"; + this.setStateActivity16.TargetStateName = "checkForCompositionsStateActivity"; + // + // confirmDialogFormActivity2 + // + this.confirmDialogFormActivity2.ContainerLabel = "Delete page"; + this.confirmDialogFormActivity2.FormDefinitionFileName = "\\Administrative\\DeletePage_ConfirmAllVersionsDeletion.xml"; + this.confirmDialogFormActivity2.Name = "confirmDialogFormActivity2"; + // + // codeActivity_SetupDeleteMultipleVersionsForm + // + this.codeActivity_SetupDeleteMultipleVersionsForm.Name = "codeActivity_SetupDeleteMultipleVersionsForm"; + this.codeActivity_SetupDeleteMultipleVersionsForm.ExecuteCode += new System.EventHandler(this.SetupDeleteMultipleVersionsForm); // // setStateActivity5 // @@ -106,32 +163,66 @@ private void InitializeComponent() this.confirmDialogFormActivity1.FormDefinitionFileName = "\\Administrative\\DeletePageStep3.xml"; this.confirmDialogFormActivity1.Name = "confirmDialogFormActivity1"; // - // codeActivity1 + // wizzardFormActivity2 // - this.codeActivity1.Name = "codeActivity1"; - this.codeActivity1.ExecuteCode += new System.EventHandler(this.confDeleteDataCodeActivity_execute); + this.wizzardFormActivity2.ContainerLabel = null; + this.wizzardFormActivity2.FormDefinitionFileName = "\\Administrative\\DeletePageStep2.xml"; + this.wizzardFormActivity2.Name = "wizzardFormActivity2"; // - // testHasSubpages + // setStateActivity7 // - this.testHasSubpages.Activities.Add(this.branchHasSubpages); - this.testHasSubpages.Activities.Add(this.branchNoSubpages); - this.testHasSubpages.Name = "testHasSubpages"; + this.setStateActivity7.Name = "setStateActivity7"; + this.setStateActivity7.TargetStateName = "finalizeStateActivity"; // - // caCheckChildren + // setStateActivity17 // - this.caCheckChildren.Description = "Checking page children"; - this.caCheckChildren.Name = "caCheckChildren"; - this.caCheckChildren.ExecuteCode += new System.EventHandler(this.codeActivity1_ExecuteCode); + this.setStateActivity17.Name = "setStateActivity17"; + this.setStateActivity17.TargetStateName = "confDeletingReferencedDataStateActivity"; // - // setStateActivity6 + // wizzardFormActivity1 // - this.setStateActivity6.Name = "setStateActivity6"; - this.setStateActivity6.TargetStateName = "finalStateActivity"; + this.wizzardFormActivity1.ContainerLabel = "Delete page"; + this.wizzardFormActivity1.FormDefinitionFileName = "\\Administrative\\DeletePageStep1.xml"; + this.wizzardFormActivity1.Name = "wizzardFormActivity1"; // - // initializeCodeActivity_ShowError_InstanceCompositions + // branchNoCompositions // - this.initializeCodeActivity_ShowError_InstanceCompositions.Name = "initializeCodeActivity_ShowError_InstanceCompositions"; - this.initializeCodeActivity_ShowError_InstanceCompositions.ExecuteCode += new System.EventHandler(this.initializeCodeActivity_ShowError_InstanceCompositions_ExecuteCode); + this.branchNoCompositions.Activities.Add(this.caCheckChildren); + this.branchNoCompositions.Activities.Add(this.setStateActivity15); + this.branchNoCompositions.Name = "branchNoCompositions"; + // + // branchHasCompositions + // + this.branchHasCompositions.Activities.Add(this.initializeCodeActivity_ShowError_InstanceCompositions); + this.branchHasCompositions.Activities.Add(this.setStateActivity6); + codecondition1.Condition += new System.EventHandler(this.HasInstanceCompositionsTest); + this.branchHasCompositions.Condition = codecondition1; + this.branchHasCompositions.Name = "branchHasCompositions"; + // + // ifElseBranchActivity_DeleteCurrentVersion + // + this.ifElseBranchActivity_DeleteCurrentVersion.Activities.Add(this.setStateActivity19); + this.ifElseBranchActivity_DeleteCurrentVersion.Name = "ifElseBranchActivity_DeleteCurrentVersion"; + // + // ifElseBranchActivity_DeleteAllVersions + // + this.ifElseBranchActivity_DeleteAllVersions.Activities.Add(this.setStateActivity10); + codecondition2.Condition += new System.EventHandler(this.ifElse_ShouldAllVersionsBeDeleted); + this.ifElseBranchActivity_DeleteAllVersions.Condition = codecondition2; + this.ifElseBranchActivity_DeleteAllVersions.Name = "ifElseBranchActivity_DeleteAllVersions"; + // + // branch_HasSingleVersion + // + this.branch_HasSingleVersion.Activities.Add(this.setStateActivity16); + this.branch_HasSingleVersion.Name = "branch_HasSingleVersion"; + // + // branch_HasMultipleVersions + // + this.branch_HasMultipleVersions.Activities.Add(this.codeActivity_SetupDeleteMultipleVersionsForm); + this.branch_HasMultipleVersions.Activities.Add(this.confirmDialogFormActivity2); + codecondition3.Condition += new System.EventHandler(this.PageHasMultpleVersions); + this.branch_HasMultipleVersions.Condition = codecondition3; + this.branch_HasMultipleVersions.Name = "branch_HasMultipleVersions"; // // branchRelatedDataDoesntExist // @@ -140,25 +231,79 @@ private void InitializeComponent() // // branchRelatedDataExist // - this.branchRelatedDataExist.Activities.Add(this.codeActivity1); this.branchRelatedDataExist.Activities.Add(this.confirmDialogFormActivity1); - codecondition2.Condition += new System.EventHandler(this.HasDataReferences); - this.branchRelatedDataExist.Condition = codecondition2; + codecondition4.Condition += new System.EventHandler(this.HasDataReferences); + this.branchRelatedDataExist.Condition = codecondition4; this.branchRelatedDataExist.Name = "branchRelatedDataExist"; // - // branchNoCompositions + // branch_deletionNotConfirmed // - this.branchNoCompositions.Activities.Add(this.caCheckChildren); - this.branchNoCompositions.Activities.Add(this.testHasSubpages); - this.branchNoCompositions.Name = "branchNoCompositions"; + this.branch_deletionNotConfirmed.Activities.Add(this.wizzardFormActivity2); + this.branch_deletionNotConfirmed.Name = "branch_deletionNotConfirmed"; // - // branchHasCompositions + // branch_DeletionConfirmed // - this.branchHasCompositions.Activities.Add(this.initializeCodeActivity_ShowError_InstanceCompositions); - this.branchHasCompositions.Activities.Add(this.setStateActivity6); - codecondition3.Condition += new System.EventHandler(this.HasInstanceCompositionsTest); - this.branchHasCompositions.Condition = codecondition3; - this.branchHasCompositions.Name = "branchHasCompositions"; + this.branch_DeletionConfirmed.Activities.Add(this.setStateActivity7); + codecondition5.Condition += new System.EventHandler(this.HasPageDeletionBeenConfirmed); + this.branch_DeletionConfirmed.Condition = codecondition5; + this.branch_DeletionConfirmed.Name = "branch_DeletionConfirmed"; + // + // branch_NoSubpages + // + this.branch_NoSubpages.Activities.Add(this.setStateActivity17); + this.branch_NoSubpages.Name = "branch_NoSubpages"; + // + // branch_HasSubpages + // + this.branch_HasSubpages.Activities.Add(this.wizzardFormActivity1); + codecondition6.Condition += new System.EventHandler(this.HasSubpages); + this.branch_HasSubpages.Condition = codecondition6; + this.branch_HasSubpages.Name = "branch_HasSubpages"; + // + // setStateActivity18 + // + this.setStateActivity18.Name = "setStateActivity18"; + this.setStateActivity18.TargetStateName = "finalStateActivity"; + // + // codeActivity_DeleteCurrentVersion + // + this.codeActivity_DeleteCurrentVersion.Name = "codeActivity_DeleteCurrentVersion"; + this.codeActivity_DeleteCurrentVersion.ExecuteCode += new System.EventHandler(this.DeleteCurrentVersion); + // + // ifElse_HasInstanceCompositions + // + this.ifElse_HasInstanceCompositions.Activities.Add(this.branchHasCompositions); + this.ifElse_HasInstanceCompositions.Activities.Add(this.branchNoCompositions); + this.ifElse_HasInstanceCompositions.Name = "ifElse_HasInstanceCompositions"; + // + // setStateActivity14 + // + this.setStateActivity14.Name = "setStateActivity14"; + this.setStateActivity14.TargetStateName = "finalStateActivity"; + // + // cancelHandleExternalEventActivity5 + // + this.cancelHandleExternalEventActivity5.EventName = "Cancel"; + this.cancelHandleExternalEventActivity5.InterfaceType = typeof(Composite.C1Console.Workflow.IFormsWorkflowEventService); + this.cancelHandleExternalEventActivity5.Name = "cancelHandleExternalEventActivity5"; + // + // ifElseActivity_DeleteAllVersions + // + this.ifElseActivity_DeleteAllVersions.Activities.Add(this.ifElseBranchActivity_DeleteAllVersions); + this.ifElseActivity_DeleteAllVersions.Activities.Add(this.ifElseBranchActivity_DeleteCurrentVersion); + this.ifElseActivity_DeleteAllVersions.Name = "ifElseActivity_DeleteAllVersions"; + // + // finishHandleExternalEventActivity4 + // + this.finishHandleExternalEventActivity4.EventName = "Finish"; + this.finishHandleExternalEventActivity4.InterfaceType = typeof(Composite.C1Console.Workflow.IFormsWorkflowEventService); + this.finishHandleExternalEventActivity4.Name = "finishHandleExternalEventActivity4"; + // + // ifElse_HasMultipleVersions + // + this.ifElse_HasMultipleVersions.Activities.Add(this.branch_HasMultipleVersions); + this.ifElse_HasMultipleVersions.Activities.Add(this.branch_HasSingleVersion); + this.ifElse_HasMultipleVersions.Name = "ifElse_HasMultipleVersions"; // // setStateActivity12 // @@ -210,11 +355,11 @@ private void InitializeComponent() this.finishHandleExternalEventActivity2.InterfaceType = typeof(Composite.C1Console.Workflow.IFormsWorkflowEventService); this.finishHandleExternalEventActivity2.Name = "finishHandleExternalEventActivity2"; // - // wizzardFormActivity2 + // ifElse_DeletionAlreadyConfirmed // - this.wizzardFormActivity2.ContainerLabel = null; - this.wizzardFormActivity2.FormDefinitionFileName = "\\Administrative\\DeletePageStep2.xml"; - this.wizzardFormActivity2.Name = "wizzardFormActivity2"; + this.ifElse_DeletionAlreadyConfirmed.Activities.Add(this.branch_DeletionConfirmed); + this.ifElse_DeletionAlreadyConfirmed.Activities.Add(this.branch_deletionNotConfirmed); + this.ifElse_DeletionAlreadyConfirmed.Name = "ifElse_DeletionAlreadyConfirmed"; // // setStateActivity3 // @@ -246,23 +391,55 @@ private void InitializeComponent() this.setStateActivity1.Name = "setStateActivity1"; this.setStateActivity1.TargetStateName = "confDeletingReferencedDataStateActivity"; // + // codeActivity_DeletingChildrenConfirmed + // + this.codeActivity_DeletingChildrenConfirmed.Name = "codeActivity_DeletingChildrenConfirmed"; + this.codeActivity_DeletingChildrenConfirmed.ExecuteCode += new System.EventHandler(this.OnDeletingChildrenConfirmed); + // // finishHandleExternalEventActivity3 // this.finishHandleExternalEventActivity3.EventName = "Finish"; this.finishHandleExternalEventActivity3.InterfaceType = typeof(Composite.C1Console.Workflow.IFormsWorkflowEventService); this.finishHandleExternalEventActivity3.Name = "finishHandleExternalEventActivity3"; // - // wizzardFormActivity1 + // ifElse_HasSubpages // - this.wizzardFormActivity1.ContainerLabel = "Delete page"; - this.wizzardFormActivity1.FormDefinitionFileName = "\\Administrative\\DeletePageStep1.xml"; - this.wizzardFormActivity1.Name = "wizzardFormActivity1"; + this.ifElse_HasSubpages.Activities.Add(this.branch_HasSubpages); + this.ifElse_HasSubpages.Activities.Add(this.branch_NoSubpages); + this.ifElse_HasSubpages.Name = "ifElse_HasSubpages"; // - // ifElse_HasInstanceCompositions + // setStateActivity8 // - this.ifElse_HasInstanceCompositions.Activities.Add(this.branchHasCompositions); - this.ifElse_HasInstanceCompositions.Activities.Add(this.branchNoCompositions); - this.ifElse_HasInstanceCompositions.Name = "ifElse_HasInstanceCompositions"; + this.setStateActivity8.Name = "setStateActivity8"; + this.setStateActivity8.TargetStateName = "confirmDeletingAllVersionsStateActivity"; + // + // stateInitializationActivity4 + // + this.stateInitializationActivity4.Activities.Add(this.codeActivity_DeleteCurrentVersion); + this.stateInitializationActivity4.Activities.Add(this.setStateActivity18); + this.stateInitializationActivity4.Name = "stateInitializationActivity4"; + // + // initializeInitializationActivity + // + this.initializeInitializationActivity.Activities.Add(this.ifElse_HasInstanceCompositions); + this.initializeInitializationActivity.Name = "initializeInitializationActivity"; + // + // versions_eventDrivenActivity_Cancel + // + this.versions_eventDrivenActivity_Cancel.Activities.Add(this.cancelHandleExternalEventActivity5); + this.versions_eventDrivenActivity_Cancel.Activities.Add(this.setStateActivity14); + this.versions_eventDrivenActivity_Cancel.Name = "versions_eventDrivenActivity_Cancel"; + // + // versions_eventDrivenActivity_Ok + // + this.versions_eventDrivenActivity_Ok.Activities.Add(this.finishHandleExternalEventActivity4); + this.versions_eventDrivenActivity_Ok.Activities.Add(this.ifElseActivity_DeleteAllVersions); + this.versions_eventDrivenActivity_Ok.Name = "versions_eventDrivenActivity_Ok"; + // + // stateInitializationActivity2 + // + this.stateInitializationActivity2.Activities.Add(this.ifElse_HasMultipleVersions); + this.stateInitializationActivity2.Name = "stateInitializationActivity2"; // // eventDrivenActivity_Finish // @@ -295,7 +472,7 @@ private void InitializeComponent() // // step2StateInitializationActivity // - this.step2StateInitializationActivity.Activities.Add(this.wizzardFormActivity2); + this.step2StateInitializationActivity.Activities.Add(this.ifElse_DeletionAlreadyConfirmed); this.step2StateInitializationActivity.Name = "step2StateInitializationActivity"; // // setStateActivity4 @@ -325,18 +502,36 @@ private void InitializeComponent() // step1EventDrivenActivity_Finish // this.step1EventDrivenActivity_Finish.Activities.Add(this.finishHandleExternalEventActivity3); + this.step1EventDrivenActivity_Finish.Activities.Add(this.codeActivity_DeletingChildrenConfirmed); this.step1EventDrivenActivity_Finish.Activities.Add(this.setStateActivity1); this.step1EventDrivenActivity_Finish.Name = "step1EventDrivenActivity_Finish"; // // step1InitializationActivity // - this.step1InitializationActivity.Activities.Add(this.wizzardFormActivity1); + this.step1InitializationActivity.Activities.Add(this.ifElse_HasSubpages); this.step1InitializationActivity.Name = "step1InitializationActivity"; // - // initializeInitializationActivity + // stateInitializationActivity3 // - this.initializeInitializationActivity.Activities.Add(this.ifElse_HasInstanceCompositions); - this.initializeInitializationActivity.Name = "initializeInitializationActivity"; + this.stateInitializationActivity3.Activities.Add(this.setStateActivity8); + this.stateInitializationActivity3.Name = "stateInitializationActivity3"; + // + // deleteCurrentVersionStateActivity + // + this.deleteCurrentVersionStateActivity.Activities.Add(this.stateInitializationActivity4); + this.deleteCurrentVersionStateActivity.Name = "deleteCurrentVersionStateActivity"; + // + // checkForCompositionsStateActivity + // + this.checkForCompositionsStateActivity.Activities.Add(this.initializeInitializationActivity); + this.checkForCompositionsStateActivity.Name = "checkForCompositionsStateActivity"; + // + // confirmDeletingAllVersionsStateActivity + // + this.confirmDeletingAllVersionsStateActivity.Activities.Add(this.stateInitializationActivity2); + this.confirmDeletingAllVersionsStateActivity.Activities.Add(this.versions_eventDrivenActivity_Ok); + this.confirmDeletingAllVersionsStateActivity.Activities.Add(this.versions_eventDrivenActivity_Cancel); + this.confirmDeletingAllVersionsStateActivity.Name = "confirmDeletingAllVersionsStateActivity"; // // confDeletingReferencedDataStateActivity // @@ -376,7 +571,7 @@ private void InitializeComponent() // // initializeStateActivity // - this.initializeStateActivity.Activities.Add(this.initializeInitializationActivity); + this.initializeStateActivity.Activities.Add(this.stateInitializationActivity3); this.initializeStateActivity.Name = "initializeStateActivity"; // // DeletePageWorkflow @@ -388,6 +583,9 @@ private void InitializeComponent() this.Activities.Add(this.eventDrivenActivity_GlobalCancel); this.Activities.Add(this.confirmationStateActivity); this.Activities.Add(this.confDeletingReferencedDataStateActivity); + this.Activities.Add(this.confirmDeletingAllVersionsStateActivity); + this.Activities.Add(this.checkForCompositionsStateActivity); + this.Activities.Add(this.deleteCurrentVersionStateActivity); this.CompletedStateName = "finalStateActivity"; this.DynamicUpdateCondition = null; this.InitialStateName = "initializeStateActivity"; @@ -396,133 +594,108 @@ private void InitializeComponent() } - #endregion - private StateInitializationActivity initializeInitializationActivity; - private StateActivity finalStateActivity; - private SetStateActivity setStateActivity3; - private StateInitializationActivity finalizeInitializationActivity; - private StateActivity finalizeStateActivity; - private CodeActivity caCheckChildren; - private CodeActivity codeActivity2; - private SetStateActivity setStateActivity4; - - private C1Console.Workflow.Activities.CancelHandleExternalEventActivity cancelHandleExternalEventActivity1; - - private EventDrivenActivity eventDrivenActivity_GlobalCancel; - private SetStateActivity setStateActivity2; - private EventDrivenActivity step2EventDrivenActivity_Finish; - private StateInitializationActivity step2StateInitializationActivity; - private StateActivity confirmationStateActivity; - private C1Console.Workflow.Activities.ConfirmDialogFormActivity wizzardFormActivity2; - private SetStateActivity setStateActivity8; - private IfElseBranchActivity branchNoSubpages; - private IfElseBranchActivity branchHasSubpages; - private IfElseActivity testHasSubpages; + #endregion + private CodeActivity codeActivity_MultipleVersionsDeletionConfirmed; + private StateActivity finalStateActivity; + private SetStateActivity setStateActivity3; + private StateInitializationActivity finalizeInitializationActivity; + private StateActivity finalizeStateActivity; + private CodeActivity codeActivity2; + private SetStateActivity setStateActivity4; + private C1Console.Workflow.Activities.CancelHandleExternalEventActivity cancelHandleExternalEventActivity1; + private EventDrivenActivity eventDrivenActivity_GlobalCancel; + private SetStateActivity setStateActivity2; + private EventDrivenActivity step2EventDrivenActivity_Finish; + private StateInitializationActivity step2StateInitializationActivity; + private StateActivity confirmationStateActivity; + private C1Console.Workflow.Activities.ConfirmDialogFormActivity wizzardFormActivity2; private C1Console.Workflow.Activities.FinishHandleExternalEventActivity finishHandleExternalEventActivity2; - private C1Console.Workflow.Activities.CloseCurrentViewActivity closeCurrentViewActivity1; - private SetStateActivity setStateActivity11; - private C1Console.Workflow.Activities.CancelHandleExternalEventActivity cancelHandleExternalEventActivity3; - private EventDrivenActivity step2EventDrivenActivity_Cancel; - - private SetStateActivity setStateActivity6; - - private CodeActivity initializeCodeActivity_ShowError_InstanceCompositions; - - private IfElseBranchActivity branchNoCompositions; - - private IfElseBranchActivity branchHasCompositions; - - private IfElseActivity ifElse_HasInstanceCompositions; - private StateActivity confDeletingReferencedDataStateActivity; - private IfElseBranchActivity branchRelatedDataDoesntExist; - private IfElseBranchActivity branchRelatedDataExist; - private IfElseActivity conditionCheckRelatedData; - private StateInitializationActivity stateInitializationActivity1; - private SetStateActivity setStateActivity5; - - private CodeActivity codeActivity1; - private SetStateActivity setStateActivity13; - private C1Console.Workflow.Activities.CancelHandleExternalEventActivity cancelHandleExternalEventActivity2; - private EventDrivenActivity eventDrivenActivity_Cancel; - private SetStateActivity setStateActivity12; - private C1Console.Workflow.Activities.FinishHandleExternalEventActivity finishHandleExternalEventActivity1; - private EventDrivenActivity eventDrivenActivity_Finish; - private C1Console.Workflow.Activities.ConfirmDialogFormActivity confirmDialogFormActivity1; - - private SetStateActivity setStateActivity7; - private SetStateActivity setStateActivity9; - private C1Console.Workflow.Activities.CancelHandleExternalEventActivity cancelHandleExternalEventActivity4; - private SetStateActivity setStateActivity1; - private C1Console.Workflow.Activities.FinishHandleExternalEventActivity finishHandleExternalEventActivity3; - private C1Console.Workflow.Activities.ConfirmDialogFormActivity wizzardFormActivity1; - private EventDrivenActivity step1EventDrivenActivity_Cancel; - private EventDrivenActivity step1EventDrivenActivity_Finish; - private StateInitializationActivity step1InitializationActivity; - private StateActivity confirmDeletingChildrenStateActivity; - + private SetStateActivity setStateActivity14; + private C1Console.Workflow.Activities.CancelHandleExternalEventActivity cancelHandleExternalEventActivity5; + private SetStateActivity setStateActivity10; + private C1Console.Workflow.Activities.FinishHandleExternalEventActivity finishHandleExternalEventActivity4; + private C1Console.Workflow.Activities.ConfirmDialogFormActivity confirmDialogFormActivity2; + private EventDrivenActivity versions_eventDrivenActivity_Cancel; + private EventDrivenActivity versions_eventDrivenActivity_Ok; + private StateInitializationActivity stateInitializationActivity2; + private StateActivity confirmDeletingAllVersionsStateActivity; + private SetStateActivity setStateActivity16; + private SetStateActivity setStateActivity17; + private IfElseBranchActivity branch_HasSingleVersion; + private IfElseBranchActivity branch_HasMultipleVersions; + private IfElseBranchActivity branch_NoSubpages; + private IfElseBranchActivity branch_HasSubpages; + private IfElseActivity ifElse_HasMultipleVersions; + private IfElseActivity ifElse_HasSubpages; + private SetStateActivity setStateActivity7; + private IfElseBranchActivity branch_deletionNotConfirmed; + private IfElseBranchActivity branch_DeletionConfirmed; + private IfElseActivity ifElse_DeletionAlreadyConfirmed; + private SetStateActivity setStateActivity15; + private CodeActivity caCheckChildren; + private SetStateActivity setStateActivity6; + private CodeActivity initializeCodeActivity_ShowError_InstanceCompositions; + private IfElseBranchActivity branchNoCompositions; + private IfElseBranchActivity branchHasCompositions; + private CodeActivity codeActivity_DeleteCurrentVersion; + private IfElseActivity ifElse_HasInstanceCompositions; + private SetStateActivity setStateActivity8; + private StateInitializationActivity stateInitializationActivity4; + private StateInitializationActivity initializeInitializationActivity; + private StateInitializationActivity stateInitializationActivity3; + private StateActivity deleteCurrentVersionStateActivity; + private StateActivity checkForCompositionsStateActivity; + private SetStateActivity setStateActivity19; + private IfElseBranchActivity ifElseBranchActivity_DeleteCurrentVersion; + private IfElseBranchActivity ifElseBranchActivity_DeleteAllVersions; + private SetStateActivity setStateActivity18; + private IfElseActivity ifElseActivity_DeleteAllVersions; + private CodeActivity codeActivity_SetupDeleteMultipleVersionsForm; + private CodeActivity codeActivity_DeletingChildrenConfirmed; private StateActivity initializeStateActivity; - - - - - - - - - - - - - - - - - - - } } diff --git a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/DeletePageWorkflow.cs b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/DeletePageWorkflow.cs index 5d27f54ef3..2794321e10 100644 --- a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/DeletePageWorkflow.cs +++ b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/DeletePageWorkflow.cs @@ -2,17 +2,15 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Transactions; using System.Workflow.Activities; -using Composite.C1Console.Actions; using Composite.C1Console.Events; using Composite.Data; using Composite.Data.ProcessControlled; using Composite.Data.Types; -using Composite.Core.ResourceSystem; using Composite.Data.Transactions; using Composite.C1Console.Workflow; - +using Composite.Core.Collections.Generic; +using Texts = Composite.Core.ResourceSystem.LocalizationFiles.Composite_Plugins_PageElementProvider; namespace Composite.Plugins.Elements.ElementProviders.PageElementProvider { @@ -25,6 +23,15 @@ public DeletePageWorkflow() InitializeComponent(); } + private static class BindingNames + { + public const string DeleteAllVersions = nameof(DeleteAllVersions); + public const string DeleteChildrenConfirmed = nameof(DeleteChildrenConfirmed); + public const string HasSubPages = nameof(HasSubPages); + public const string DeleteMessageText = nameof(DeleteMessageText); + public const string ReferencedData = nameof(ReferencedData); + } + private void HasInstanceCompositionsTest(object sender, ConditionalEventArgs e) { @@ -34,7 +41,7 @@ private void HasInstanceCompositionsTest(object sender, ConditionalEventArgs e) private void HasSubpages(object sender, ConditionalEventArgs e) { - e.Result = this.GetBinding("HasSubPages"); + e.Result = this.GetBinding(BindingNames.HasSubPages); } @@ -44,7 +51,7 @@ private void HasDataReferences(object sender, ConditionalEventArgs e) DataEntityToken dataEntityToken = (DataEntityToken)this.EntityToken; IPage selectedPage = (IPage)dataEntityToken.Data; - List dataToDelete = new List(); + var dataToDelete = new List(); IEnumerable subtree = new[] { selectedPage }.Concat(selectedPage.GetSubChildren()); @@ -80,7 +87,7 @@ private void HasDataReferences(object sender, ConditionalEventArgs e) e.Result = brokenReferences.Count > 0; if (brokenReferences.Count > 0) { - Bindings.Add("ReferencedData", DataReferenceFacade.GetBrokenReferencesReport(brokenReferences)); + Bindings.Add(BindingNames.ReferencedData, DataReferenceFacade.GetBrokenReferencesReport(brokenReferences)); } } @@ -93,125 +100,107 @@ private void codeActivity1_ExecuteCode(object sender, EventArgs e) bool hasChildren = PageServices.GetChildren(selectedPage.Id).Any(); - Dictionary bindings = new Dictionary(); - bindings.Add("HasSubPages", hasChildren); - bindings.Add("DeleteAllSubPages", false); - bindings.Add("DeleteMessageText", string.Format(StringResourceSystemFacade.GetString("Composite.Plugins.PageElementProvider", "DeletePageStep2.Text"), selectedPage.Title)); - this.Bindings = bindings; + this.Bindings.AddDictionary(new Dictionary + { + {BindingNames.HasSubPages, hasChildren}, + {BindingNames.DeleteMessageText, Texts.DeletePageStep2_Text(selectedPage.Title)} + }); } private void codeActivity2_ExecuteCode(object sender, EventArgs e) { - bool hasSubPages = this.GetBinding("HasSubPages"); + bool hasSubPages = this.GetBinding(BindingNames.HasSubPages); DataEntityToken dataEntityToken = (DataEntityToken)this.EntityToken; IPage selectedPage = (IPage)dataEntityToken.Data; - using (TransactionScope transactionScope = TransactionsFacade.CreateNewScope()) + + if (!DataFacade.WillDeleteSucceed(selectedPage)) { - if (DataFacade.WillDeleteSucceed(selectedPage) == false) - { - this.ShowMessage( - DialogType.Error, - StringResourceSystemFacade.GetString("Composite.Plugins.PageElementProvider", "DeletePageWorkflow.CascadeDeleteErrorTitle"), - StringResourceSystemFacade.GetString("Composite.Plugins.PageElementProvider", "DeletePageWorkflow.CascadeDeleteErrorMessage") - ); + this.ShowMessage( + DialogType.Error, + Texts.DeletePageWorkflow_CascadeDeleteErrorTitle, + Texts.DeletePageWorkflow_CascadeDeleteErrorMessage + ); - return; - } + return; + } - List cultures = DataLocalizationFacade.ActiveLocalizationCultures.ToList(); - cultures.Remove(selectedPage.DataSourceId.LocaleScope); + if (hasSubPages) + { + List pagesToDelete = selectedPage.GetSubChildren().ToList(); - if (hasSubPages) + if (pagesToDelete.Any(page => !DataFacade.WillDeleteSucceed(page))) { - List pagesToDelete = selectedPage.GetSubChildren().ToList(); - - foreach (IPage page in pagesToDelete) - { - if (DataFacade.WillDeleteSucceed(page) == false) - { - this.ShowMessage( - DialogType.Error, - StringResourceSystemFacade.GetString("Composite.Plugins.PageElementProvider", "DeletePageWorkflow.CascadeDeleteErrorTitle"), - StringResourceSystemFacade.GetString("Composite.Plugins.PageElementProvider", "DeletePageWorkflow.CascadeDeleteErrorMessage") - ); - - return; - } - } + this.ShowMessage(DialogType.Error, + Texts.DeletePageWorkflow_CascadeDeleteErrorTitle, + Texts.DeletePageWorkflow_CascadeDeleteErrorMessage); - foreach (IPage page in pagesToDelete) - { - if (ExistInOtherLocale(cultures, page) == false) - { - RemoveAllFolderAndMetaDataDefinitions(page); - } - - page.DeletePageStructure(); - ProcessControllerFacade.FullDelete(page); - } + return; } + } - if (ExistInOtherLocale(cultures, selectedPage) == false) - { - RemoveAllFolderAndMetaDataDefinitions(selectedPage); - } + var parentTreeRefresher = this.CreateParentTreeRefresher(); + parentTreeRefresher.PostRefreshMessages(selectedPage.GetDataEntityToken(), 2); - ParentTreeRefresher parentTreeRefresher = this.CreateParentTreeRefresher(); - parentTreeRefresher.PostRefreshMesseges(selectedPage.GetDataEntityToken(), 2); + PageServices.DeletePage(selectedPage); + } - selectedPage.DeletePageStructure(); - ProcessControllerFacade.FullDelete(selectedPage); - transactionScope.Complete(); - } + private void initializeCodeActivity_ShowError_InstanceCompositions_ExecuteCode(object sender, EventArgs e) + { + this.ShowMessage( + DialogType.Error, + Texts.DeletePageWorkflow_HasCompositionsTitle, + Texts.DeletePageWorkflow_HasCompositionsMessage + ); } - - private bool ExistInOtherLocale(List cultures, IPage page) + private void PageHasMultpleVersions(object sender, ConditionalEventArgs e) { - foreach (CultureInfo localeCultureInfo in cultures) - { - using (new DataScope(localeCultureInfo)) - { - if (Composite.Data.PageManager.GetPageById(page.Id) != null) - { - return true; - } - } - } + DataEntityToken dataEntityToken = (DataEntityToken)this.EntityToken; + IPage selectedPage = (IPage)dataEntityToken.Data; - return false; + Guid pageId = selectedPage.Id; + + e.Result = DataFacade.GetData().Count(p => p.Id == pageId) > 1; } + private void HasPageDeletionBeenConfirmed(object sender, ConditionalEventArgs e) + { + Func isTrueBinding = bindingName => + Bindings.ContainsKey(bindingName) + && (bool) Bindings[bindingName]; + + e.Result = isTrueBinding(BindingNames.DeleteAllVersions) + || isTrueBinding(BindingNames.DeleteChildrenConfirmed); + } - private void RemoveAllFolderAndMetaDataDefinitions(IPage page) + private void DeleteCurrentVersion(object sender, EventArgs e) { - foreach (Type folderType in page.GetDefinedFolderTypes()) - { - page.RemoveFolderDefinition(folderType, true); - } + var dataEntityToken = (DataEntityToken)this.EntityToken; + IPage selectedPage = (IPage)dataEntityToken.Data; - foreach (Tuple metaDataTypeAndName in page.GetDefinedMetaDataTypeAndNames()) - { - page.RemoveMetaDataDefinition(metaDataTypeAndName.Item2, true); - } + PageServices.DeletePage(selectedPage.Id, selectedPage.VersionId, selectedPage.DataSourceId.LocaleScope); + + var parentTreeRefresher = this.CreateParentTreeRefresher(); + parentTreeRefresher.PostRefreshMessages(selectedPage.GetDataEntityToken(), 2); } + private void ifElse_ShouldAllVersionsBeDeleted(object sender, ConditionalEventArgs e) + { + e.Result = (bool)Bindings[BindingNames.DeleteAllVersions]; + } - private void initializeCodeActivity_ShowError_InstanceCompositions_ExecuteCode(object sender, EventArgs e) + private void SetupDeleteMultipleVersionsForm(object sender, EventArgs e) { - this.ShowMessage( - DialogType.Error, - "${Composite.Plugins.PageElementProvider, DeletePageWorkflow.HasCompositionsTitle}", - "${Composite.Plugins.PageElementProvider, DeletePageWorkflow.HasCompositionsMessage}" - ); + Bindings[BindingNames.DeleteAllVersions] = false; } - private void confDeleteDataCodeActivity_execute(object sender, EventArgs e) + private void OnDeletingChildrenConfirmed(object sender, EventArgs e) { + Bindings[BindingNames.DeleteChildrenConfirmed] = true; } } } diff --git a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/DeletePageWorkflow.layout b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/DeletePageWorkflow.layout index 8881aabe2b..e129253667 100644 --- a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/DeletePageWorkflow.layout +++ b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/DeletePageWorkflow.layout @@ -1,171 +1,220 @@ - + - - + + - + - - - - - + + + + + - + - - - - - - - - - - - - + + + - - - + + + - - - - - + + + + + - - - - - + + + + + + + + + + + + + + - - - - - + + + + + - - - - - + + + + + - - - + + + + + - - - - - + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + + + + + + + + + + + - + - - + - + - - - - - - - - - - - - - - - + - - - - - - - - - - - + - - + + + - + - - + + - + - + - - - + + + @@ -176,61 +225,155 @@ - + - + - + + + + + + + + + + + + + + - + - - + + - + - - + + - + - + - + - + - - + - + - + - + - - + + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/EditPageWorkflow.cs b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/EditPageWorkflow.cs index 0295c46c1f..3f274b0821 100644 --- a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/EditPageWorkflow.cs +++ b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/EditPageWorkflow.cs @@ -11,7 +11,6 @@ using Composite.C1Console.Forms; using Composite.C1Console.Forms.DataServices; using Composite.C1Console.Forms.Flows; -using Composite.C1Console.Scheduling; using Composite.C1Console.Security; using Composite.C1Console.Users; using Composite.C1Console.Workflow; @@ -32,7 +31,6 @@ using Composite.Data.GeneratedTypes; using Composite.Data.ProcessControlled; using Composite.Data.ProcessControlled.ProcessControllers.GenericPublishProcessController; -using Composite.Data.PublishScheduling; using Composite.Data.Transactions; using Composite.Data.Types; using Composite.Data.Validation; @@ -50,11 +48,12 @@ public sealed partial class EditPageWorkflow : FormsWorkflow public EditPageWorkflow() { InitializeComponent(); + InitializeExtensions(); } private static DataTypeDescriptorFormsHelper CreateDataTypeDescriptorFormsHelper(IPageMetaDataDefinition pageMetaDataDefinition, DataTypeDescriptor dataTypeDescriptor) { - var bindingPrefix = string.Format("{0}:{1}.{2}", pageMetaDataDefinition.Name, dataTypeDescriptor.Namespace, dataTypeDescriptor.Name); + var bindingPrefix = $"{pageMetaDataDefinition.Name}:{dataTypeDescriptor.Namespace}.{dataTypeDescriptor.Name}"; var helper = new DataTypeDescriptorFormsHelper(dataTypeDescriptor, bindingPrefix); @@ -149,7 +148,7 @@ private void editStateCodeActivity_ExecuteCode(object sender, EventArgs e) if (!BindingExist("SelectedPage")) { selectedPage = GetDataItemFromEntityToken(); - + if (selectedPage.PublicationStatus == GenericPublishProcessController.Published) { selectedPage.PublicationStatus = GenericPublishProcessController.Draft; @@ -270,7 +269,7 @@ private void editStateCodeActivity_ExecuteCode(object sender, EventArgs e) } - var contents = DataFacade.GetData(f => f.PageId == selectedPage.Id).ToList(); + var contents = DataFacade.GetData(f => f.PageId == selectedPage.Id && f.VersionId == selectedPage.VersionId).ToList(); var namedXhtmlFragments = contents.ToDictionary(content => content.PlaceHolderId, content => content.Content ?? ""); @@ -280,18 +279,6 @@ private void editStateCodeActivity_ExecuteCode(object sender, EventArgs e) UpdateBinding("StateOptions", transitionNames); - var existingPagePublishSchedule = PublishScheduleHelper.GetPublishSchedule(typeof (IPage), - selectedPage.Id.ToString(), - UserSettings.ActiveLocaleCultureInfo.Name); - - UpdateBinding("PublishDate", existingPagePublishSchedule?.PublishDate); - - var existingPageUnpublishSchedule = PublishScheduleHelper.GetUnpublishSchedule(typeof(IPage), - selectedPage.Id.ToString(), - UserSettings.ActiveLocaleCultureInfo.Name); - - UpdateBinding("UnpublishDate", existingPageUnpublishSchedule?.UnpublishDate); - var formDefinition = formDocument.GetDocumentAsString(); DeliverFormData( @@ -317,7 +304,7 @@ private void saveCodeActivity_ExecuteCode(object sender, EventArgs e) var updateTreeRefresher = CreateUpdateTreeRefresher(EntityToken); var selectedPage = GetBinding("SelectedPage"); - var originalPage = DataFacade.GetData(f => f.Id == selectedPage.Id).SingleOrDefault(); + var originalPage = DataFacade.GetData(f => f.Id == selectedPage.Id && f.VersionId == selectedPage.VersionId).SingleOrDefault(); var viewLabelUpdated = originalPage == null || selectedPage.MenuTitle != originalPage.MenuTitle @@ -330,9 +317,6 @@ private void saveCodeActivity_ExecuteCode(object sender, EventArgs e) var dataValidated = true; - WorkflowInstance publishWorkflowInstance = null; - WorkflowInstance unpublishWorkflowInstance = null; - try { using (var transactionScope = TransactionsFacade.CreateNewScope()) @@ -341,8 +325,6 @@ private void saveCodeActivity_ExecuteCode(object sender, EventArgs e) if (dataValidated) { - PublishControlledHelper.HandlePublishUnpublishWorkflows(selectedPage, UserSettings.ActiveLocaleCultureInfo.Name, PublishDate, UnpublishDate, ref publishWorkflowInstance, ref unpublishWorkflowInstance); - if (selectedPage.PageTypeId != originalPage.PageTypeId) { // Adding metadata fields @@ -396,7 +378,7 @@ private void saveCodeActivity_ExecuteCode(object sender, EventArgs e) DataFacade.Update(originalPage); var contentDictionary = GetBinding>("NamedXhtmlFragments"); - var existingContents = DataFacade.GetData(f => f.PageId == selectedPage.Id).ToList(); + var existingContents = DataFacade.GetData(f => f.PageId == selectedPage.Id && f.VersionId == selectedPage.VersionId).ToList(); foreach (var existingContent in existingContents) { @@ -416,6 +398,7 @@ private void saveCodeActivity_ExecuteCode(object sender, EventArgs e) { var newContent = DataFacade.BuildNew(); newContent.PageId = selectedPage.Id; + newContent.VersionId = selectedPage.VersionId; newContent.PlaceHolderId = contentDictionaryElement.Key; newContent.Content = contentDictionaryElement.Value; newContent.SourceCultureName = UserSettings.ActiveLocaleCultureInfo.Name; @@ -428,36 +411,15 @@ private void saveCodeActivity_ExecuteCode(object sender, EventArgs e) transactionScope.Complete(); } - if (publishWorkflowInstance != null) - { - publishWorkflowInstance.Start(); - WorkflowFacade.RunWorkflow(publishWorkflowInstance); - } - - if (unpublishWorkflowInstance != null) - { - unpublishWorkflowInstance.Start(); - WorkflowFacade.RunWorkflow(unpublishWorkflowInstance); - } - if (_doPublish) { - if (publishWorkflowInstance == null || PublishDate < DateTime.Now) - { - var actionToken = new GenericPublishProcessController.PublishActionToken(); + var actionToken = new GenericPublishProcessController.PublishActionToken(); - var serviceContainer = WorkflowFacade.GetFlowControllerServicesContainer(WorkflowEnvironment.WorkflowInstanceId); + var serviceContainer = WorkflowFacade.GetFlowControllerServicesContainer(WorkflowEnvironment.WorkflowInstanceId); - ActionExecutorFacade.Execute(EntityToken, actionToken, serviceContainer); + ActionExecutorFacade.Execute(EntityToken, actionToken, serviceContainer); - treeviewRequiresRefreshing = false; - } - else - { - var title = StringResourceSystemFacade.GetString("Composite.Management", "Website.Forms.Administrative.EditPage.PublishDatePreventPublishTitle"); - var message = StringResourceSystemFacade.GetString("Composite.Management", "Website.Forms.Administrative.EditPage.PublishDatePreventPublish"); - ShowMessage(DialogType.Warning, title, message); - } + treeviewRequiresRefreshing = false; } if (treeviewRequiresRefreshing) @@ -559,10 +521,6 @@ private bool PrepareAddUpdateMetaData(IPage selectedPage, IDictionary GetBinding("PublishDate"); - - private DateTime? UnpublishDate => GetBinding("UnpublishDate"); - private void editPreviewCodeActivity_ExecuteCode(object sender, EventArgs e) { var serviceContainer = WorkflowFacade.GetFlowControllerServicesContainer(WorkflowEnvironment.WorkflowInstanceId); @@ -578,6 +536,7 @@ private void editPreviewCodeActivity_ExecuteCode(object sender, EventArgs e) { var content = DataFacade.BuildNew(); content.PageId = selectedPage.Id; + content.VersionId = selectedPage.VersionId; content.PlaceHolderId = placeHolderContent.Key; content.Content = placeHolderContent.Value; contents.Add(content); @@ -600,9 +559,7 @@ private static void TrimFieldValues(IPage page) page.Title = page.Title.Trim(); page.MenuTitle = page.MenuTitle.Trim(); page.UrlTitle = page.UrlTitle.Trim(); - - var friendlyURL = page.FriendlyUrl; - page.FriendlyUrl = friendlyURL != null ? friendlyURL.Trim() : null; + page.FriendlyUrl = page.FriendlyUrl?.Trim(); } @@ -711,7 +668,7 @@ private static string GetText(string key) private void PageStillExists(object sender, ConditionalEventArgs e) { var selectedPage = GetBinding("SelectedPage"); - var originalPage = DataFacade.GetData(f => f.Id == selectedPage.Id).SingleOrDefault(); + var originalPage = DataFacade.GetData(f => f.Id == selectedPage.Id && f.VersionId == selectedPage.VersionId).SingleOrDefault(); e.Result = originalPage != null; } diff --git a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/LocalizePageWorkflow.cs b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/LocalizePageWorkflow.cs index 40845a73d6..9b2c3c2858 100644 --- a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/LocalizePageWorkflow.cs +++ b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/LocalizePageWorkflow.cs @@ -42,7 +42,9 @@ private void initializeCodeActivity_Copy_ExecuteCode(object sender, EventArgs e) using (new DataScope(sourceCultureInfo)) { - Guid sourcePageId = ((IPage)castedEntityToken.Data).Id; + var pageFromEntityToken = (IPage) castedEntityToken.Data; + Guid sourcePageId = pageFromEntityToken.Id; + Guid sourcePageVersionId = pageFromEntityToken.VersionId; using (new DataScope(DataScopeIdentifier.Administrated)) { @@ -51,7 +53,9 @@ private void initializeCodeActivity_Copy_ExecuteCode(object sender, EventArgs e) using (new DataScope(sourcePage.DataSourceId.DataScopeIdentifier)) { - sourcePagePlaceholders = DataFacade.GetData(f => f.PageId == sourcePageId).ToList(); + sourcePagePlaceholders = DataFacade + .GetData(f => f.PageId == sourcePageId && f.VersionId == sourcePageVersionId) + .ToList(); sourceMetaDataSet = sourcePage.GetMetaData().ToList(); } } diff --git a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/PagePublishSchedulerWorkflow.cs b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/PagePublishSchedulerWorkflow.cs deleted file mode 100644 index 496ce1e50c..0000000000 --- a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/PagePublishSchedulerWorkflow.cs +++ /dev/null @@ -1,172 +0,0 @@ -using System; -using System.ComponentModel; -using System.Globalization; -using System.Linq; -using System.Threading.Tasks; -using System.Workflow.Activities; -using System.Workflow.Runtime; -using Composite.C1Console.Scheduling; -using Composite.C1Console.Workflow; -using Composite.Core; -using Composite.Core.Threading; -using Composite.Data; -using Composite.Data.Transactions; -using Composite.Data.Types; - - - -namespace Composite.Plugins.Elements.ElementProviders.PageElementProvider -{ - [Obsolete("Is replaced by Composite.C1Console.Scheduling.PagePublishSchedulerWorkflow")] - [AllowPersistingWorkflow(WorkflowPersistingType.Shutdown)] - public sealed partial class PagePublishSchedulerWorkflow : StateMachineWorkflowActivity - { - private static readonly string LogTitle = typeof (PagePublishSchedulerWorkflow).Name; - - private DateTime _publishDate; - private Guid _pageId; - private string _localeName; - - private static readonly object _conversionSyncRoot = new object(); - - - public PagePublishSchedulerWorkflow() - { - InitializeComponent(); - } - - protected override void OnActivityExecutionContextLoad(IServiceProvider provider) - { - base.OnActivityExecutionContextLoad(provider); - - if (PageId == Guid.Empty) return; - - Guid workflowInstanceId = WorkflowInstanceId; - - Task.Factory.StartNew(async () => - { - await Task.Delay(3000); - ConvertObsoleteWorkflow(workflowInstanceId); - }); - } - - [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public Guid PageId - { - get { return _pageId; } - set { _pageId = value; } - } - - - - [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public DateTime PublishDate - { - get { return _publishDate; } - set { _publishDate = value; } - } - - - - [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public string LocaleName - { - get { return _localeName; } - set { _localeName = value; } - } - - - - private void initializeCodeActivity_ExecuteCode(object sender, EventArgs e) - { - var delayActivity = (DelayActivity)this.GetActivityByName("waitDelayActivity"); - delayActivity.TimeoutDuration = new TimeSpan(0); - } - - - - private void finalizeCodeActivity_ExecuteCode(object sender, EventArgs e) - { - ConvertObsoleteWorkflow(WorkflowInstanceId); - } - - private void ConvertObsoleteWorkflow(Guid workflowInstanceId) - { - if(PageId == Guid.Empty) return; - - Log.LogVerbose(LogTitle, "Converting an obsolete page publishing workflow '{0}' into a new one.", workflowInstanceId); - - if (ConvertOldPublishingWorkflows(PageId, LocaleName)) - { - PageId = Guid.Empty; - } - } - - internal static bool ConvertOldPublishingWorkflows(Guid pageId, string localeName) - { - lock (_conversionSyncRoot) - try - { - using (GlobalInitializerFacade.CoreIsInitializedScope) - using (ThreadDataManager.EnsureInitialize()) - { - using (new DataScope(DataScopeIdentifier.Administrated, CultureInfo.CreateSpecificCulture(localeName))) - { - using (var transaction = TransactionsFacade.CreateNewScope()) - { - var pagePublishSchedule = - (from ps in DataFacade.GetData() - where ps.PageId == pageId && - ps.LocaleCultureName == localeName - select ps).SingleOrDefault(); - - var pageUnpublishSchedule = - (from ps in DataFacade.GetData() - where ps.PageId == pageId && - ps.LocaleCultureName == localeName - select ps).SingleOrDefault(); - - if (pagePublishSchedule == null && pageUnpublishSchedule == null) - { - return true; - } - - if (pagePublishSchedule != null) - { - DataFacade.Delete(pagePublishSchedule); - } - - - if (pageUnpublishSchedule != null) - { - DataFacade.Delete(pageUnpublishSchedule); - } - - DateTime? publishDate = pagePublishSchedule != null ? pagePublishSchedule.PublishDate : (DateTime?)null; - DateTime? unpublishDate = pageUnpublishSchedule != null ? pageUnpublishSchedule.UnpublishDate : (DateTime?)null; - - - IPage page = DataFacade.GetData(p => p.Id == pageId).FirstOrDefault(); - Verify.IsNotNull(page, "The page with the id {0} does not exist", pageId); - - WorkflowInstance publishWorkflowInstance = null; - WorkflowInstance unpublishWorkflowInstance = null; - - PublishControlledHelper.HandlePublishUnpublishWorkflows(page, localeName, publishDate, unpublishDate, - ref publishWorkflowInstance, ref unpublishWorkflowInstance); - - transaction.Complete(); - } - } - } - - return true; - } - catch (Exception ex) - { - Log.LogError(LogTitle, ex); - return false; - } - } - } -} diff --git a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/PagePublishSchedulerWorkflow.designer.cs b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/PagePublishSchedulerWorkflow.designer.cs deleted file mode 100644 index 36644ef9cb..0000000000 --- a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/PagePublishSchedulerWorkflow.designer.cs +++ /dev/null @@ -1,282 +0,0 @@ -using System; -using System.ComponentModel; -using System.ComponentModel.Design; -using System.Collections; -using System.Drawing; -using System.Reflection; -using System.Workflow.ComponentModel.Compiler; -using System.Workflow.ComponentModel.Serialization; -using System.Workflow.ComponentModel; -using System.Workflow.ComponentModel.Design; -using System.Workflow.Runtime; -using System.Workflow.Activities; -using System.Workflow.Activities.Rules; -using Composite.C1Console.Workflow; - -namespace Composite.Plugins.Elements.ElementProviders.PageElementProvider -{ - partial class PagePublishSchedulerWorkflow - { - #region Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this� method with the code editor. - /// - [System.Diagnostics.DebuggerNonUserCode] - private void InitializeComponent() - { - this.CanModifyActivities = true; - this.setStateActivity3 = new System.Workflow.Activities.SetStateActivity(); - this.finalizeCodeActivity = new System.Workflow.Activities.CodeActivity(); - this.setStateActivity2 = new System.Workflow.Activities.SetStateActivity(); - this.waitDelayActivity = new System.Workflow.Activities.DelayActivity(); - this.setStateActivity1 = new System.Workflow.Activities.SetStateActivity(); - this.initializeCodeActivity = new System.Workflow.Activities.CodeActivity(); - this.finalizeStateInitializationActivity = new System.Workflow.Activities.StateInitializationActivity(); - this.waitEventDrivenActivity_Timeout = new System.Workflow.Activities.EventDrivenActivity(); - this.waitStateInitializationActivity = new System.Workflow.Activities.StateInitializationActivity(); - this.initializeStateInitializationActivity = new System.Workflow.Activities.StateInitializationActivity(); - this.setStateActivity19 = new System.Workflow.Activities.SetStateActivity(); - this.cancelHandleExternalEventActivity1 = new Composite.C1Console.Workflow.Activities.CancelHandleExternalEventActivity(); - this.finalizeStateActivity = new System.Workflow.Activities.StateActivity(); - this.waitStateActivity = new System.Workflow.Activities.StateActivity(); - this.initializeStateActivity = new System.Workflow.Activities.StateActivity(); - this.eventDrivenActivity_GlobalCancel = new System.Workflow.Activities.EventDrivenActivity(); - this.finishState = new System.Workflow.Activities.StateActivity(); - // - // setStateActivity3 - // - this.setStateActivity3.Name = "setStateActivity3"; - this.setStateActivity3.TargetStateName = "finishState"; - // - // finalizeCodeActivity - // - this.finalizeCodeActivity.Name = "finalizeCodeActivity"; - this.finalizeCodeActivity.ExecuteCode += new System.EventHandler(this.finalizeCodeActivity_ExecuteCode); - // - // setStateActivity2 - // - this.setStateActivity2.Name = "setStateActivity2"; - this.setStateActivity2.TargetStateName = "finalizeStateActivity"; - // - // waitDelayActivity - // - this.waitDelayActivity.Name = "waitDelayActivity"; - this.waitDelayActivity.TimeoutDuration = System.TimeSpan.Parse("00:00:15"); - // - // setStateActivity1 - // - this.setStateActivity1.Name = "setStateActivity1"; - this.setStateActivity1.TargetStateName = "waitStateActivity"; - // - // initializeCodeActivity - // - this.initializeCodeActivity.Name = "initializeCodeActivity"; - this.initializeCodeActivity.ExecuteCode += new System.EventHandler(this.initializeCodeActivity_ExecuteCode); - // - // finalizeStateInitializationActivity - // - this.finalizeStateInitializationActivity.Activities.Add(this.finalizeCodeActivity); - this.finalizeStateInitializationActivity.Activities.Add(this.setStateActivity3); - this.finalizeStateInitializationActivity.Name = "finalizeStateInitializationActivity"; - // - // waitEventDrivenActivity_Timeout - // - this.waitEventDrivenActivity_Timeout.Activities.Add(this.waitDelayActivity); - this.waitEventDrivenActivity_Timeout.Activities.Add(this.setStateActivity2); - this.waitEventDrivenActivity_Timeout.Name = "waitEventDrivenActivity_Timeout"; - // - // waitStateInitializationActivity - // - this.waitStateInitializationActivity.Name = "waitStateInitializationActivity"; - // - // initializeStateInitializationActivity - // - this.initializeStateInitializationActivity.Activities.Add(this.initializeCodeActivity); - this.initializeStateInitializationActivity.Activities.Add(this.setStateActivity1); - this.initializeStateInitializationActivity.Name = "initializeStateInitializationActivity"; - // - // setStateActivity19 - // - this.setStateActivity19.Name = "setStateActivity19"; - this.setStateActivity19.TargetStateName = "finishState"; - // - // cancelHandleExternalEventActivity1 - // - this.cancelHandleExternalEventActivity1.EventName = "Cancel"; - this.cancelHandleExternalEventActivity1.InterfaceType = typeof(Composite.C1Console.Workflow.IFormsWorkflowEventService); - this.cancelHandleExternalEventActivity1.Name = "cancelHandleExternalEventActivity1"; - // - // finalizeStateActivity - // - this.finalizeStateActivity.Activities.Add(this.finalizeStateInitializationActivity); - this.finalizeStateActivity.Name = "finalizeStateActivity"; - // - // waitStateActivity - // - this.waitStateActivity.Activities.Add(this.waitStateInitializationActivity); - this.waitStateActivity.Activities.Add(this.waitEventDrivenActivity_Timeout); - this.waitStateActivity.Name = "waitStateActivity"; - // - // initializeStateActivity - // - this.initializeStateActivity.Activities.Add(this.initializeStateInitializationActivity); - this.initializeStateActivity.Name = "initializeStateActivity"; - // - // eventDrivenActivity_GlobalCancel - // - this.eventDrivenActivity_GlobalCancel.Activities.Add(this.cancelHandleExternalEventActivity1); - this.eventDrivenActivity_GlobalCancel.Activities.Add(this.setStateActivity19); - this.eventDrivenActivity_GlobalCancel.Name = "eventDrivenActivity_GlobalCancel"; - // - // finishState - // - this.finishState.Name = "finishState"; - // - // PagePublishSchedulerWorkflow - // - this.Activities.Add(this.finishState); - this.Activities.Add(this.eventDrivenActivity_GlobalCancel); - this.Activities.Add(this.initializeStateActivity); - this.Activities.Add(this.waitStateActivity); - this.Activities.Add(this.finalizeStateActivity); - this.CompletedStateName = "finishState"; - this.DynamicUpdateCondition = null; - this.InitialStateName = "initializeStateActivity"; - this.Name = "PagePublishSchedulerWorkflow"; - this.CanModifyActivities = false; - - } - - #endregion - - private StateActivity finishState; - private SetStateActivity setStateActivity19; - private Composite.C1Console.Workflow.Activities.CancelHandleExternalEventActivity cancelHandleExternalEventActivity1; - private StateInitializationActivity waitStateInitializationActivity; - private StateInitializationActivity initializeStateInitializationActivity; - private StateActivity waitStateActivity; - private StateActivity initializeStateActivity; - private DelayActivity waitDelayActivity; - private SetStateActivity setStateActivity1; - private EventDrivenActivity waitEventDrivenActivity_Timeout; - private CodeActivity finalizeCodeActivity; - private StateInitializationActivity finalizeStateInitializationActivity; - private StateActivity finalizeStateActivity; - private SetStateActivity setStateActivity3; - private SetStateActivity setStateActivity2; - private CodeActivity initializeCodeActivity; - private EventDrivenActivity eventDrivenActivity_GlobalCancel; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - } -} diff --git a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/PagePublishSchedulerWorkflow.layout b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/PagePublishSchedulerWorkflow.layout deleted file mode 100644 index a5ab69e09c..0000000000 --- a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/PagePublishSchedulerWorkflow.layout +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/PageUnpublishSchedulerWorkflow.cs b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/PageUnpublishSchedulerWorkflow.cs deleted file mode 100644 index 7c4bfa7ffe..0000000000 --- a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/PageUnpublishSchedulerWorkflow.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System; -using System.ComponentModel; -using System.Threading.Tasks; -using System.Workflow.Activities; -using Composite.C1Console.Workflow; -using Composite.Core; - - -namespace Composite.Plugins.Elements.ElementProviders.PageElementProvider -{ - [Obsolete("Is replaced by Composite.C1Console.Scheduling.PageUnpublishSchedulerWorkflow")] - [AllowPersistingWorkflow(WorkflowPersistingType.Shutdown)] - public sealed partial class PageUnpublishSchedulerWorkflow : StateMachineWorkflowActivity - { - private static readonly string LogTitle = typeof(PageUnpublishSchedulerWorkflow).Name; - - private DateTime _unpublishDate; - private Guid _pageId; - private string _localeName; - - - public PageUnpublishSchedulerWorkflow() - { - InitializeComponent(); - } - - - protected override void OnActivityExecutionContextLoad(IServiceProvider provider) - { - base.OnActivityExecutionContextLoad(provider); - - if (PageId == Guid.Empty) return; - - Guid workflowInstanceId = WorkflowInstanceId; - - Task.Factory.StartNew(async () => - { - await Task.Delay(3000); - ConvertObsoleteWorkflow(workflowInstanceId); - }); - } - - - [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public Guid PageId - { - get { return _pageId; } - set { _pageId = value; } - } - - - - [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public DateTime UnpublishDate - { - get { return _unpublishDate; } - set { _unpublishDate = value; } - } - - - - [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public string LocaleName - { - get { return _localeName; } - set { _localeName = value; } - } - - - - private void initializeCodeActivity_ExecuteCode(object sender, EventArgs e) - { - var delayActivity = (DelayActivity)this.GetActivityByName("waitDelayActivity"); - - delayActivity.TimeoutDuration = new TimeSpan(0); - } - - - private void finalizeCodeActivity_ExecuteCode(object sender, EventArgs e) - { - ConvertObsoleteWorkflow(WorkflowInstanceId); - } - - private void ConvertObsoleteWorkflow(Guid workflowInstanceId) - { - if (PageId == Guid.Empty) return; - - Log.LogVerbose(LogTitle, "Converting an obsolete page unpublishing workflow '{0}' into a new one.", workflowInstanceId); - - if (PagePublishSchedulerWorkflow.ConvertOldPublishingWorkflows(PageId, LocaleName)) - { - PageId = Guid.Empty; - } - } - } -} diff --git a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/PageUnpublishSchedulerWorkflow.designer.cs b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/PageUnpublishSchedulerWorkflow.designer.cs deleted file mode 100644 index 14fb4ed96d..0000000000 --- a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/PageUnpublishSchedulerWorkflow.designer.cs +++ /dev/null @@ -1,282 +0,0 @@ -using System; -using System.ComponentModel; -using System.ComponentModel.Design; -using System.Collections; -using System.Drawing; -using System.Reflection; -using System.Workflow.ComponentModel.Compiler; -using System.Workflow.ComponentModel.Serialization; -using System.Workflow.ComponentModel; -using System.Workflow.ComponentModel.Design; -using System.Workflow.Runtime; -using System.Workflow.Activities; -using System.Workflow.Activities.Rules; -using Composite.C1Console.Workflow; - -namespace Composite.Plugins.Elements.ElementProviders.PageElementProvider -{ - partial class PageUnpublishSchedulerWorkflow - { - #region Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this� method with the code editor. - /// - [System.Diagnostics.DebuggerNonUserCode] - private void InitializeComponent() - { - this.CanModifyActivities = true; - this.setStateActivity3 = new System.Workflow.Activities.SetStateActivity(); - this.finalizeCodeActivity = new System.Workflow.Activities.CodeActivity(); - this.setStateActivity2 = new System.Workflow.Activities.SetStateActivity(); - this.waitDelayActivity = new System.Workflow.Activities.DelayActivity(); - this.setStateActivity1 = new System.Workflow.Activities.SetStateActivity(); - this.initializeCodeActivity = new System.Workflow.Activities.CodeActivity(); - this.finalizeStateInitializationActivity = new System.Workflow.Activities.StateInitializationActivity(); - this.waitEventDrivenActivity_Timeout = new System.Workflow.Activities.EventDrivenActivity(); - this.waitStateInitializationActivity = new System.Workflow.Activities.StateInitializationActivity(); - this.initializeStateInitializationActivity = new System.Workflow.Activities.StateInitializationActivity(); - this.setStateActivity19 = new System.Workflow.Activities.SetStateActivity(); - this.cancelHandleExternalEventActivity1 = new Composite.C1Console.Workflow.Activities.CancelHandleExternalEventActivity(); - this.finalizeStateActivity = new System.Workflow.Activities.StateActivity(); - this.waitStateActivity = new System.Workflow.Activities.StateActivity(); - this.initializeStateActivity = new System.Workflow.Activities.StateActivity(); - this.eventDrivenActivity_GlobalCancel = new System.Workflow.Activities.EventDrivenActivity(); - this.finishState = new System.Workflow.Activities.StateActivity(); - // - // setStateActivity3 - // - this.setStateActivity3.Name = "setStateActivity3"; - this.setStateActivity3.TargetStateName = "finishState"; - // - // finalizeCodeActivity - // - this.finalizeCodeActivity.Name = "finalizeCodeActivity"; - this.finalizeCodeActivity.ExecuteCode += new System.EventHandler(this.finalizeCodeActivity_ExecuteCode); - // - // setStateActivity2 - // - this.setStateActivity2.Name = "setStateActivity2"; - this.setStateActivity2.TargetStateName = "finalizeStateActivity"; - // - // waitDelayActivity - // - this.waitDelayActivity.Name = "waitDelayActivity"; - this.waitDelayActivity.TimeoutDuration = System.TimeSpan.Parse("00:00:15"); - // - // setStateActivity1 - // - this.setStateActivity1.Name = "setStateActivity1"; - this.setStateActivity1.TargetStateName = "waitStateActivity"; - // - // initializeCodeActivity - // - this.initializeCodeActivity.Name = "initializeCodeActivity"; - this.initializeCodeActivity.ExecuteCode += new System.EventHandler(this.initializeCodeActivity_ExecuteCode); - // - // finalizeStateInitializationActivity - // - this.finalizeStateInitializationActivity.Activities.Add(this.finalizeCodeActivity); - this.finalizeStateInitializationActivity.Activities.Add(this.setStateActivity3); - this.finalizeStateInitializationActivity.Name = "finalizeStateInitializationActivity"; - // - // waitEventDrivenActivity_Timeout - // - this.waitEventDrivenActivity_Timeout.Activities.Add(this.waitDelayActivity); - this.waitEventDrivenActivity_Timeout.Activities.Add(this.setStateActivity2); - this.waitEventDrivenActivity_Timeout.Name = "waitEventDrivenActivity_Timeout"; - // - // waitStateInitializationActivity - // - this.waitStateInitializationActivity.Name = "waitStateInitializationActivity"; - // - // initializeStateInitializationActivity - // - this.initializeStateInitializationActivity.Activities.Add(this.initializeCodeActivity); - this.initializeStateInitializationActivity.Activities.Add(this.setStateActivity1); - this.initializeStateInitializationActivity.Name = "initializeStateInitializationActivity"; - // - // setStateActivity19 - // - this.setStateActivity19.Name = "setStateActivity19"; - this.setStateActivity19.TargetStateName = "finishState"; - // - // cancelHandleExternalEventActivity1 - // - this.cancelHandleExternalEventActivity1.EventName = "Cancel"; - this.cancelHandleExternalEventActivity1.InterfaceType = typeof(Composite.C1Console.Workflow.IFormsWorkflowEventService); - this.cancelHandleExternalEventActivity1.Name = "cancelHandleExternalEventActivity1"; - // - // finalizeStateActivity - // - this.finalizeStateActivity.Activities.Add(this.finalizeStateInitializationActivity); - this.finalizeStateActivity.Name = "finalizeStateActivity"; - // - // waitStateActivity - // - this.waitStateActivity.Activities.Add(this.waitStateInitializationActivity); - this.waitStateActivity.Activities.Add(this.waitEventDrivenActivity_Timeout); - this.waitStateActivity.Name = "waitStateActivity"; - // - // initializeStateActivity - // - this.initializeStateActivity.Activities.Add(this.initializeStateInitializationActivity); - this.initializeStateActivity.Name = "initializeStateActivity"; - // - // eventDrivenActivity_GlobalCancel - // - this.eventDrivenActivity_GlobalCancel.Activities.Add(this.cancelHandleExternalEventActivity1); - this.eventDrivenActivity_GlobalCancel.Activities.Add(this.setStateActivity19); - this.eventDrivenActivity_GlobalCancel.Name = "eventDrivenActivity_GlobalCancel"; - // - // finishState - // - this.finishState.Name = "finishState"; - // - // PagePublishSchedulerWorkflow - // - this.Activities.Add(this.finishState); - this.Activities.Add(this.eventDrivenActivity_GlobalCancel); - this.Activities.Add(this.initializeStateActivity); - this.Activities.Add(this.waitStateActivity); - this.Activities.Add(this.finalizeStateActivity); - this.CompletedStateName = "finishState"; - this.DynamicUpdateCondition = null; - this.InitialStateName = "initializeStateActivity"; - this.Name = "PagePublishSchedulerWorkflow"; - this.CanModifyActivities = false; - - } - - #endregion - - private StateActivity finishState; - private SetStateActivity setStateActivity19; - private Composite.C1Console.Workflow.Activities.CancelHandleExternalEventActivity cancelHandleExternalEventActivity1; - private StateInitializationActivity waitStateInitializationActivity; - private StateInitializationActivity initializeStateInitializationActivity; - private StateActivity waitStateActivity; - private StateActivity initializeStateActivity; - private DelayActivity waitDelayActivity; - private SetStateActivity setStateActivity1; - private EventDrivenActivity waitEventDrivenActivity_Timeout; - private CodeActivity finalizeCodeActivity; - private StateInitializationActivity finalizeStateInitializationActivity; - private StateActivity finalizeStateActivity; - private SetStateActivity setStateActivity3; - private SetStateActivity setStateActivity2; - private CodeActivity initializeCodeActivity; - private EventDrivenActivity eventDrivenActivity_GlobalCancel; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - } -} diff --git a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/PageUnpublishSchedulerWorkflow.layout b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/PageUnpublishSchedulerWorkflow.layout deleted file mode 100644 index a5ab69e09c..0000000000 --- a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/PageUnpublishSchedulerWorkflow.layout +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/UndoUnpublishedChangesWorkflow.cs b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/UndoUnpublishedChangesWorkflow.cs index 9e326dce06..67e1345391 100644 --- a/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/UndoUnpublishedChangesWorkflow.cs +++ b/Composite.Workflows/Plugins/Elements/ElementProviders/PageElementProvider/UndoUnpublishedChangesWorkflow.cs @@ -31,21 +31,24 @@ private void undoCodeActivity_Undo_ExecuteCode(object sender, EventArgs e) List administrativeCompositions = administrativePage.GetMetaData(DataScopeIdentifier.Administrated).ToList(); List publicCompositions = publicPage.GetMetaData(DataScopeIdentifier.Public).ToList(); + Guid pageId = administrativePage.Id; + Guid versionId = administrativePage.Id; + List administrativePlaceholders; - using (DataScope dataScope = new DataScope(DataScopeIdentifier.Administrated)) + using (new DataScope(DataScopeIdentifier.Administrated)) { administrativePlaceholders = (from ph in DataFacade.GetData() - where ph.PageId == administrativePage.Id + where ph.PageId == pageId && ph.VersionId == versionId select ph).ToList(); } List publicPlaceholders; - using (DataScope dataScope = new DataScope(DataScopeIdentifier.Public)) + using (new DataScope(DataScopeIdentifier.Public)) { publicPlaceholders = (from ph in DataFacade.GetData() - where ph.PageId == publicPage.Id + where ph.PageId == pageId && ph.VersionId == versionId select ph).ToList(); } diff --git a/Composite.Workflows/Properties/AssemblyInfo.cs b/Composite.Workflows/Properties/AssemblyInfo.cs index 8e8883acfa..ce7907a1c0 100644 --- a/Composite.Workflows/Properties/AssemblyInfo.cs +++ b/Composite.Workflows/Properties/AssemblyInfo.cs @@ -32,6 +32,6 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("5.1.*")] +[assembly: AssemblyVersion("5.2.*")] [assembly: InternalsVisibleTo("UpgradePackage")] \ No newline at end of file diff --git a/Composite/AspNet/Razor/CompositeC1WebPage.cs b/Composite/AspNet/Razor/CompositeC1WebPage.cs index e9d278be86..0e468a38d8 100644 --- a/Composite/AspNet/Razor/CompositeC1WebPage.cs +++ b/Composite/AspNet/Razor/CompositeC1WebPage.cs @@ -15,7 +15,7 @@ namespace Composite.AspNet.Razor public abstract class CompositeC1WebPage : WebPage, IDisposable { private bool _disposed; - private readonly DataConnection _data; + private DataConnection _data; /// /// Initializes a new instance of the class. @@ -28,36 +28,24 @@ protected CompositeC1WebPage() /// /// Gets a object. /// - public DataConnection Data - { - get { return _data; } - } + public DataConnection Data => _data; /// /// Gets a object. /// - public SitemapNavigator Sitemap - { - get { return Data.SitemapNavigator; } - } + public SitemapNavigator Sitemap => Data.SitemapNavigator; /// /// Gets the home page node. /// - public PageNode HomePageNode - { - get { return Sitemap.CurrentHomePageNode; } - } + public PageNode HomePageNode => Sitemap.CurrentHomePageNode; /// /// Gets the current page node. /// - public PageNode CurrentPageNode - { - get { return Sitemap.CurrentPageNode; } - } + public PageNode CurrentPageNode => Sitemap.CurrentPageNode; /// @@ -147,6 +135,14 @@ private FunctionContextContainer GetFunctionContext() return PageData[RazorHelper.PageContext_FunctionContextContainer]; } + public override void ExecutePageHierarchy() + { + base.ExecutePageHierarchy(); + + _data.Dispose(); + _data = null; + } + /// public void Dispose() { @@ -158,15 +154,14 @@ public void Dispose() /// protected virtual void Dispose(bool disposing) { - if (!_disposed) - { - if (disposing) - { - _data.Dispose(); - } - - _disposed = true; - } + if (_disposed) return; + + if (disposing) + { + _data?.Dispose(); + } + + _disposed = true; } /// diff --git a/Composite/C1Console/Actions/Data/DataActionTokenResolver.cs b/Composite/C1Console/Actions/Data/DataActionTokenResolver.cs index 3bb2258039..c918d96069 100644 --- a/Composite/C1Console/Actions/Data/DataActionTokenResolver.cs +++ b/Composite/C1Console/Actions/Data/DataActionTokenResolver.cs @@ -64,7 +64,20 @@ public ActionToken Resolve(IData data, ActionIdentifier actionIdentifier) return conditionalAction.GetActionToken(data); } } - + + return ResolveDefault(data, actionIdentifier); + } + + /// + /// Resolves a default action of the given type for a given data item + /// + /// The data item + /// The action identifier + /// + public ActionToken ResolveDefault(IData data, ActionIdentifier actionIdentifier) + { + var interfaces = GetOrderedInterfaces(data.DataSourceId.InterfaceType); + foreach (var type in interfaces) { var defaultAction = _defaultActions?.LastOrDefault(f => f.Check(type, data, actionIdentifier)); diff --git a/Composite/C1Console/Actions/Data/DataActionTokenResolverFacade.cs b/Composite/C1Console/Actions/Data/DataActionTokenResolverFacade.cs index 328f739af3..dd541aa320 100644 --- a/Composite/C1Console/Actions/Data/DataActionTokenResolverFacade.cs +++ b/Composite/C1Console/Actions/Data/DataActionTokenResolverFacade.cs @@ -16,6 +16,13 @@ public static ActionToken Resolve(IData data, ActionIdentifier actionIdentifier) { return GetDataActionTokenResolverService().Resolve(data, actionIdentifier); } + + /// + public static ActionToken ResolveDefault(IData data, ActionIdentifier actionIdentifier) + { + return GetDataActionTokenResolverService().ResolveDefault(data, actionIdentifier); + } + /// /// Use this to assign a deafult action to a certain data type /// diff --git a/Composite/C1Console/Elements/ElementProviderHelpers/AssociatedDataElementProviderHelper/AssociatedDataElementProviderHelper.cs b/Composite/C1Console/Elements/ElementProviderHelpers/AssociatedDataElementProviderHelper/AssociatedDataElementProviderHelper.cs index 2ed6a434da..34b9bf11e5 100644 --- a/Composite/C1Console/Elements/ElementProviderHelpers/AssociatedDataElementProviderHelper/AssociatedDataElementProviderHelper.cs +++ b/Composite/C1Console/Elements/ElementProviderHelpers/AssociatedDataElementProviderHelper/AssociatedDataElementProviderHelper.cs @@ -311,7 +311,7 @@ public List GetChildren(T data, EntityToken parentEntityToken) public List GetChildren(AssociatedDataElementProviderHelperEntityToken entityToken, bool includeForeignFolders) { - IData data = entityToken.GetData(); + IData data = entityToken.GetDataList().FirstOrDefault(); Type interfaceType = TypeManager.TryGetType(entityToken.Payload); if (data == null) return new List(); diff --git a/Composite/C1Console/Elements/ElementProviderHelpers/AssociatedDataElementProviderHelper/AssociatedDataElementProviderHelperEntityToken.cs b/Composite/C1Console/Elements/ElementProviderHelpers/AssociatedDataElementProviderHelper/AssociatedDataElementProviderHelperEntityToken.cs index 53f6e5e67f..c22cf8a156 100644 --- a/Composite/C1Console/Elements/ElementProviderHelpers/AssociatedDataElementProviderHelper/AssociatedDataElementProviderHelperEntityToken.cs +++ b/Composite/C1Console/Elements/ElementProviderHelpers/AssociatedDataElementProviderHelper/AssociatedDataElementProviderHelperEntityToken.cs @@ -84,6 +84,17 @@ public IData GetData() return data; } + /// + public IEnumerable GetDataList() + { + Type type = TypeManager.GetType(this.Type); + + object id = ValueTypeConverter.Convert(this.Id, type.GetKeyProperties()[0].PropertyType); + + var datas = DataFacade.TryGetDataVersionsByUniqueKey(type, id); + + return datas; + } /// public override string Serialize() diff --git a/Composite/C1Console/Elements/ElementProviderHelpers/AssociatedDataElementProviderHelper/AssociatedDataElementProviderHelperSecurityAncestorProvider.cs b/Composite/C1Console/Elements/ElementProviderHelpers/AssociatedDataElementProviderHelper/AssociatedDataElementProviderHelperSecurityAncestorProvider.cs index 78ff778f3f..d1d5318f26 100644 --- a/Composite/C1Console/Elements/ElementProviderHelpers/AssociatedDataElementProviderHelper/AssociatedDataElementProviderHelperSecurityAncestorProvider.cs +++ b/Composite/C1Console/Elements/ElementProviderHelpers/AssociatedDataElementProviderHelper/AssociatedDataElementProviderHelperSecurityAncestorProvider.cs @@ -12,7 +12,7 @@ public IEnumerable GetParents(EntityToken entityToken) { var castedEntityToken = (AssociatedDataElementProviderHelperEntityToken)entityToken; - var dataItem = castedEntityToken.GetData(); + var dataItem = castedEntityToken.GetDataList().FirstOrDefault(); // Data item may not exist in current language return dataItem != null ? new[] { dataItem.GetDataEntityToken() } : Enumerable.Empty(); diff --git a/Composite/C1Console/Elements/ElementVisualizedData.cs b/Composite/C1Console/Elements/ElementVisualizedData.cs index d7b28db2f2..a7cfa35f44 100644 --- a/Composite/C1Console/Elements/ElementVisualizedData.cs +++ b/Composite/C1Console/Elements/ElementVisualizedData.cs @@ -37,5 +37,16 @@ public sealed class ElementVisualizedData /// Tooltip for the element - typically shown when hovering the element /// public string ToolTip { get; set; } + + /// + /// Having a common ElementBundle across elements will make the client bundle them up as a single node, and allow the user to select a specific element via a drop down, showing individual BundleElementName values + /// + public string ElementBundle { get; set; } + + /// + /// When bundling elements this field is used to identify this specific element for selection + /// + public string BundleElementName { get; set; } + } } diff --git a/Composite/C1Console/Elements/IServiceUrlToEntityTokenMapper.cs b/Composite/C1Console/Elements/IServiceUrlToEntityTokenMapper.cs new file mode 100644 index 0000000000..2f2c93c3da --- /dev/null +++ b/Composite/C1Console/Elements/IServiceUrlToEntityTokenMapper.cs @@ -0,0 +1,33 @@ +using Composite.C1Console.Security; + +namespace Composite.C1Console.Elements +{ + /// + /// Allows Data Scope Services to Add or Clean their parameters to or from the URL and update a entity token with their associate properties + /// + public interface IServiceUrlToEntityTokenMapper + { + /// + /// Gets a URL and Returns the url with parametres associated with an entity token, or original URL if current entity token does not support this kind of entity token. + /// + /// The url. + /// The entity token. + /// A URL that will display the data item - this can be an "internal" URL which is later transformed by a IInternalUrlConverter. Intended for public consumption. + string ProcessUrl(string url, EntityToken entityToken); + + /// + /// Updates an entity token according to a url. + /// + /// The url. + /// The entity token. + /// + EntityToken TryGetEntityToken(string url, ref EntityToken entityToken); + + /// + /// Gets a url and cleans it up from its parameters. + /// + /// The url. + /// + string CleanUrl(ref string url); + } +} diff --git a/Composite/C1Console/Elements/UrlToEntityTokenFacade.cs b/Composite/C1Console/Elements/UrlToEntityTokenFacade.cs index fb57d5401f..089b22f973 100644 --- a/Composite/C1Console/Elements/UrlToEntityTokenFacade.cs +++ b/Composite/C1Console/Elements/UrlToEntityTokenFacade.cs @@ -1,8 +1,8 @@ -using System; -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Linq; using Composite.C1Console.Security; using Composite.Core; +using Composite.Core.Extensions; namespace Composite.C1Console.Elements { @@ -11,7 +11,10 @@ namespace Composite.C1Console.Elements /// public static class UrlToEntityTokenFacade { + private const string LogTitle = nameof(UrlToEntityTokenFacade); + private static readonly ConcurrentBag _mappers = new ConcurrentBag(); + private static readonly ConcurrentBag _serviceMappers = new ConcurrentBag(); /// /// Returns a url associated with an entity token, or null if current entity token does not support this kind of entity token. @@ -20,9 +23,12 @@ public static class UrlToEntityTokenFacade /// URL for public consumption public static string TryGetUrl(EntityToken entityToken) { - return _mappers.Select(mapper => mapper.TryGetUrl(entityToken)).FirstOrDefault(url => url != null); + var theUrl = _mappers.Select(mapper => mapper.TryGetUrl(entityToken)).FirstOrDefault(url => url != null); + + return ProcessUrlWithServiceMappers(theUrl, entityToken); } + /// /// Returns a url / tooling settings associated with an entity token to be used in the C1 Console browser, or null if current entity token does not support this kind of entity token. /// @@ -31,10 +37,29 @@ public static string TryGetUrl(EntityToken entityToken) /// URL for public consumption public static BrowserViewSettings TryGetBrowserViewSettings(EntityToken entityToken, bool showPublishedView) { - return _mappers.Select(mapper => mapper.TryGetBrowserViewSettings(entityToken, showPublishedView)).FirstOrDefault(settings => settings != null && settings.Url != null); + var theBrowserSetting = _mappers.Select(mapper => + mapper.TryGetBrowserViewSettings(entityToken, showPublishedView)) + .FirstOrDefault(settings => settings?.Url != null); + + if (theBrowserSetting == null) return null; + + var originalUrl = theBrowserSetting.Url; + theBrowserSetting.Url = ProcessUrlWithServiceMappers(originalUrl, entityToken); + + return theBrowserSetting; } + private static string ProcessUrlWithServiceMappers(string url, EntityToken entityToken) + { + _serviceMappers.ForEach(service => + { + url = service.ProcessUrl(url, entityToken); + }); + + return url; + } + /// /// Returns an entity token associated with a url, or null if current does not support this kind of entity token. /// @@ -42,7 +67,10 @@ public static BrowserViewSettings TryGetBrowserViewSettings(EntityToken entityTo /// public static EntityToken TryGetEntityToken(string url) { - return _mappers.Select(mapper => mapper.TryGetEntityToken(url)).FirstOrDefault(entityToken => entityToken != null); + var originalUrl = url; + url = _serviceMappers.Select(sm => sm.CleanUrl(ref url)).Last(); + var baseEntityToken = _mappers.Select(mapper => mapper.TryGetEntityToken(url)).FirstOrDefault(entityToken => entityToken != null); + return _serviceMappers.Select(sm => sm.TryGetEntityToken(originalUrl, ref baseEntityToken)).Last(); } /// @@ -51,16 +79,34 @@ public static EntityToken TryGetEntityToken(string url) /// public static void Register(IUrlToEntityTokenMapper mapper) { - Verify.ArgumentNotNull(mapper, "mapper"); + Verify.ArgumentNotNull(mapper, nameof(mapper)); if (_mappers.Count > 100) { - Log.LogWarning("UrlToEntityTokenFacade", "More than 100 implementations of {0}-s registered: possible memory leak. Registered type: {1}", - typeof(IUrlToEntityTokenMapper).Name, mapper.GetType().FullName); + Log.LogWarning(LogTitle, "More than 100 implementations of {0}-s registered: possible memory leak. Registered type: {1}", + nameof(IUrlToEntityTokenMapper), mapper.GetType().FullName); return; } _mappers.Add(mapper); } + + /// + /// Register an implementation of + /// + /// + public static void Register(IServiceUrlToEntityTokenMapper serviceMapper) + { + Verify.ArgumentNotNull(serviceMapper, nameof(serviceMapper)); + + if (_serviceMappers.Count > 100) + { + Log.LogWarning(LogTitle, "More than 100 implementations of {0}-s registered: possible memory leak. Registered type: {1}", + nameof(IServiceUrlToEntityTokenMapper), serviceMapper.GetType().FullName); + return; + } + + _serviceMappers.Add(serviceMapper); + } } } diff --git a/Composite/C1Console/Events/OpenSlideViewQueueItem.cs b/Composite/C1Console/Events/OpenSlideViewQueueItem.cs new file mode 100644 index 0000000000..0fd630f0ab --- /dev/null +++ b/Composite/C1Console/Events/OpenSlideViewQueueItem.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using Composite.Core.ResourceSystem; +using Composite.C1Console.Security; + +namespace Composite.C1Console.Events +{ + /// + /// + /// + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + [Serializable] + public sealed class OpenSlideViewQueueItem : IConsoleMessageQueueItem + { + /// + public string ViewId { get; set; } + + /// + public string EntityToken { get; set; } + + /// + public string Url { get; set; } + + } +} diff --git a/Composite/C1Console/Events/ViewType.cs b/Composite/C1Console/Events/ViewType.cs index 7c42da0fb9..f138e2d5d5 100644 --- a/Composite/C1Console/Events/ViewType.cs +++ b/Composite/C1Console/Events/ViewType.cs @@ -1,9 +1,9 @@ namespace Composite.C1Console.Events { - /// + /// /// /// - [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public enum ViewType { /// diff --git a/Composite/C1Console/Forms/CoreUiControls/BaseSelectorUiControl.cs b/Composite/C1Console/Forms/CoreUiControls/BaseSelectorUiControl.cs index 16174341b7..ff79073bbc 100644 --- a/Composite/C1Console/Forms/CoreUiControls/BaseSelectorUiControl.cs +++ b/Composite/C1Console/Forms/CoreUiControls/BaseSelectorUiControl.cs @@ -8,7 +8,7 @@ namespace Composite.C1Console.Forms.CoreUiControls { internal abstract class BaseSelectorUiControl : UiControl { - public BaseSelectorUiControl() + protected BaseSelectorUiControl() { this.OptionsKeyField = "."; this.OptionsLabelField = "."; @@ -59,9 +59,7 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c { string val = value as string; - val = val.ToLowerInvariant(); - - switch (val) + switch (val.ToLowerInvariant()) { case "bindtoobject": return SelectorBindingType.BindToObject; @@ -70,7 +68,7 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c return SelectorBindingType.BindToKeyFieldValue; default: - throw new FormatException(String.Format("{0} is not a valid Selector BindingType value - use BindToObject or BindToKeyFieldValue", value)); + throw new FormatException($"{value} is not a valid Selector BindingType value - use {nameof(SelectorBindingType.BindToObject)} or {nameof(SelectorBindingType.BindToKeyFieldValue)}"); } } } diff --git a/Composite/C1Console/Forms/CoreUiControls/BoolSelectorUiControl.cs b/Composite/C1Console/Forms/CoreUiControls/BoolSelectorUiControl.cs index c5adf85688..c3d8f88589 100644 --- a/Composite/C1Console/Forms/CoreUiControls/BoolSelectorUiControl.cs +++ b/Composite/C1Console/Forms/CoreUiControls/BoolSelectorUiControl.cs @@ -8,16 +8,20 @@ namespace Composite.C1Console.Forms.CoreUiControls [ControlValueProperty("IsTrue")] internal abstract class BoolSelectorUiControl : UiControl { - [BindableProperty()] - [FormsProperty()] + [BindableProperty] + [FormsProperty] public bool IsTrue { get; set; } - [FormsProperty()] + [FormsProperty] public string TrueLabel { get; set; } - [FormsProperty()] + [FormsProperty] public string FalseLabel { get; set; } + + [BindableProperty] + [FormsProperty] + public EventHandler SelectionChangedEventHandler { get; set; } } } diff --git a/Composite/C1Console/Forms/CoreUiControls/DateSelectorUiControl.cs b/Composite/C1Console/Forms/CoreUiControls/DateSelectorUiControl.cs index 1209b4ef1e..1c56c2aa78 100644 --- a/Composite/C1Console/Forms/CoreUiControls/DateSelectorUiControl.cs +++ b/Composite/C1Console/Forms/CoreUiControls/DateSelectorUiControl.cs @@ -8,11 +8,14 @@ namespace Composite.C1Console.Forms.CoreUiControls [ControlValueProperty("Date")] internal abstract class DateTimeSelectorUiControl : UiControl { - [BindableProperty()] - [FormsProperty()] + [BindableProperty] + [FormsProperty] public DateTime? Date { get; set; } - [FormsProperty()] + [FormsProperty] public bool ReadOnly { get; set; } + + [FormsProperty] + public bool Required { get; set; } } } diff --git a/Composite/C1Console/Forms/DataServices/FormDefinitionFileMarkupProvider.cs b/Composite/C1Console/Forms/DataServices/FormDefinitionFileMarkupProvider.cs index 2b609409fd..744915c7d3 100644 --- a/Composite/C1Console/Forms/DataServices/FormDefinitionFileMarkupProvider.cs +++ b/Composite/C1Console/Forms/DataServices/FormDefinitionFileMarkupProvider.cs @@ -14,7 +14,7 @@ namespace Composite.C1Console.Forms.DataServices /// /// [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] - public class FormDefinitionFileMarkupProvider : IFormMarkupProvider + public class FormDefinitionFileMarkupProvider : IFormMarkupProvider, ITestAutomationLocatorInformation { private readonly string _formPath; @@ -27,6 +27,14 @@ public FormDefinitionFileMarkupProvider(string formPath) _formPath = formPath; } + /// + public string TestAutomationLocator + { + get + { + return Path.GetFileNameWithoutExtension(_formPath); + } + } /// public XmlReader GetReader() diff --git a/Composite/C1Console/Forms/Flows/FormFlowRenderingService.cs b/Composite/C1Console/Forms/Flows/FormFlowRenderingService.cs index 96cb3ee1a0..39b4c8e814 100644 --- a/Composite/C1Console/Forms/Flows/FormFlowRenderingService.cs +++ b/Composite/C1Console/Forms/Flows/FormFlowRenderingService.cs @@ -20,7 +20,7 @@ public void RerenderView() public bool HasFieldMessages { - get { return (_bindingPathedMessages != null && _bindingPathedMessages.Count > 0); } + get { return _bindingPathedMessages != null && _bindingPathedMessages.Count > 0; } } @@ -38,10 +38,7 @@ public void ShowFieldMessages(Dictionary bindingPathedMessages) } - internal Dictionary BindingPathedMessages - { - get { return _bindingPathedMessages; } - } + public Dictionary BindingPathedMessages => _bindingPathedMessages; public void ShowFieldMessage(string fieldBindingPath, string message) diff --git a/Composite/C1Console/Forms/Flows/IFormFlowRenderingService.cs b/Composite/C1Console/Forms/Flows/IFormFlowRenderingService.cs index c87edaad15..e237ea8004 100644 --- a/Composite/C1Console/Forms/Flows/IFormFlowRenderingService.cs +++ b/Composite/C1Console/Forms/Flows/IFormFlowRenderingService.cs @@ -1,8 +1,9 @@ -using Composite.C1Console.Actions; +using System.Collections.Generic; +using Composite.C1Console.Actions; namespace Composite.C1Console.Forms.Flows { - /// + /// /// /// [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] @@ -22,5 +23,8 @@ public interface IFormFlowRenderingService : IFlowControllerService /// void SetSaveStatus(bool succeeded); + + /// + Dictionary BindingPathedMessages { get; } } } diff --git a/Composite/C1Console/Forms/Flows/IUiContainer.cs b/Composite/C1Console/Forms/Flows/IUiContainer.cs index 2f550289c6..6e8cf4d623 100644 --- a/Composite/C1Console/Forms/Flows/IUiContainer.cs +++ b/Composite/C1Console/Forms/Flows/IUiContainer.cs @@ -12,6 +12,7 @@ IUiControl Render( IDictionary eventHandlerBindings, string containerLabel, string containerLabelField, + string containerTooltip, ResourceHandle containerIcon); } } diff --git a/Composite/C1Console/Forms/FormTreeCompiler.cs b/Composite/C1Console/Forms/FormTreeCompiler.cs index f4371f3778..0d29945e07 100644 --- a/Composite/C1Console/Forms/FormTreeCompiler.cs +++ b/Composite/C1Console/Forms/FormTreeCompiler.cs @@ -23,10 +23,11 @@ public sealed class FormTreeCompiler private CompileContext _context; private Dictionary _bindingObjects; - private IUiControl _uiControl = null; - private CompileTreeNode _rootCompilerNode = null; + private IUiControl _uiControl; + private CompileTreeNode _rootCompilerNode; private string _label; + private string _tooltip; private string _iconHandle; @@ -81,11 +82,13 @@ public void Compile(XDocument doc, IFormChannelIdentifier channel, Dictionary @@ -135,16 +138,13 @@ public Dictionary SaveAndValidateControlProperties() public Dictionary GetBindingToClientIDMapping() { var result = new Dictionary(); - FormFlowUiDefinitionRenderer.ResolveBindingPathToCliendIDMappings(_uiControl as IWebUiControl, result); + FormFlowUiDefinitionRenderer.ResolveBindingPathToClientIDMappings(_uiControl as IWebUiControl, result); return result; } /// - public IUiControl UiControl - { - get { return _uiControl; } - } + public IUiControl UiControl => _uiControl; /// @@ -157,6 +157,10 @@ public string Label } + /// + public string Tooltip => _tooltip; + + /// public ResourceHandle Icon { @@ -175,22 +179,16 @@ public ResourceHandle Icon string[] resourceParts = _iconHandle.Split(','); if (resourceParts.Length != 2) throw new InvalidOperationException( - string.Format("Invalid icon resource name '{0}'. Only one comma expected.", _iconHandle)); + $"Invalid icon resource name '{_iconHandle}'. Only one comma expected."); return new ResourceHandle(resourceParts[0].Trim(), resourceParts[1].Trim()); } } /// - public Dictionary BindingObjects - { - get { return _bindingObjects; } - } + public Dictionary BindingObjects => _bindingObjects; /// - public CompileTreeNode RootCompileTreeNode - { - get { return _rootCompilerNode; } - } + public CompileTreeNode RootCompileTreeNode => _rootCompilerNode; } } diff --git a/Composite/C1Console/Forms/Foundation/FormTreeCompiler/CompilePhases/ExtractUiArtifactsPhase.cs b/Composite/C1Console/Forms/Foundation/FormTreeCompiler/CompilePhases/ExtractUiArtifactsPhase.cs index b0c925eedb..1e77f48ac2 100644 --- a/Composite/C1Console/Forms/Foundation/FormTreeCompiler/CompilePhases/ExtractUiArtifactsPhase.cs +++ b/Composite/C1Console/Forms/Foundation/FormTreeCompiler/CompilePhases/ExtractUiArtifactsPhase.cs @@ -6,16 +6,17 @@ namespace Composite.C1Console.Forms.Foundation.FormTreeCompiler.CompilePhases { internal sealed class ExtractUiArtifactsPhase { - public void ExtractUiArtifacts(CompileTreeNode node, out IUiControl uiControl, out string label, out string iconhandle ) + public void ExtractUiArtifacts(CompileTreeNode node, out IUiControl uiControl, out string label, out string tooltip, out string iconhandle ) { foreach (PropertyCompileTreeNode n in node.DefaultProperties) { if (n.Value is LayoutProducer) { - LayoutProducer lp = (n.Value as LayoutProducer); + var lp = (LayoutProducer) n.Value; uiControl = lp.UiControl; label = lp.label; iconhandle = lp.iconhandle; + tooltip = lp.tooltip; return; } diff --git a/Composite/C1Console/Forms/Foundation/FormTreeCompiler/PropertyAssigner.cs b/Composite/C1Console/Forms/Foundation/FormTreeCompiler/PropertyAssigner.cs index 707bf02542..1315343007 100644 --- a/Composite/C1Console/Forms/Foundation/FormTreeCompiler/PropertyAssigner.cs +++ b/Composite/C1Console/Forms/Foundation/FormTreeCompiler/PropertyAssigner.cs @@ -375,24 +375,30 @@ private static void EvaluteObjectBinding(ElementCompileTreeNode element, Propert private static void ResolveBindingObject(ElementCompileTreeNode element, PropertyCompileTreeNode property, CompileContext compileContext, string bindSourceName, out object bindingObject, out Type bindType) { - string typeName = ((BindingsProducer)compileContext.BindingsProducer).GetTypeNameByName(bindSourceName); + var bindingProducer = (BindingsProducer) compileContext.BindingsProducer; + if (bindingProducer == null) + { + throw new FormCompileException($"Failed to resolve binding object {bindSourceName} - the binding producer is null", element, property); + } + + string typeName = bindingProducer.GetTypeNameByName(bindSourceName); if (typeName == null) { - throw new FormCompileException(string.Format("{1} binds to an undeclared binding name '{0}'. All binding names must be declared in /cms:formdefinition/cms:bindings", bindSourceName, element.XmlSourceNodeInformation.XPath), element, property); + throw new FormCompileException($"{element.XmlSourceNodeInformation.XPath} binds to an undeclared binding name '{bindSourceName}'. All binding names must be declared in /cms:formdefinition/cms:bindings", element, property); } bindType = TypeManager.TryGetType(typeName); if (bindType == null) { - throw new FormCompileException(string.Format("The form binding '{0}' is declared as an unknown type '{1}'", bindSourceName, typeName), element, property); + throw new FormCompileException($"The form binding '{bindSourceName}' is declared as an unknown type '{typeName}'", element, property); } - bool? optional = ((BindingsProducer)compileContext.BindingsProducer).GetOptionalValueByName(bindSourceName); + bool? optional = bindingProducer.GetOptionalValueByName(bindSourceName); bindingObject = compileContext.GetBindingObject(bindSourceName); if (!optional.Value && !compileContext.BindingObjectExists(bindSourceName)) { - throw new FormCompileException(string.Format("The binding object named '{0}' not found in the input dictionary", bindSourceName), element, property); + throw new FormCompileException($"The binding object named '{bindSourceName}' not found in the input dictionary", element, property); } if (bindingObject != null) @@ -400,7 +406,7 @@ private static void ResolveBindingObject(ElementCompileTreeNode element, Propert Type bindingObjectType = bindingObject.GetType(); if (!bindType.IsAssignableOrLazyFrom(bindingObjectType)) { - throw new FormCompileException(string.Format("The binding object named '{0}' from the input dictionary is not of expected type '{1}', but '{2}'", bindSourceName, bindType.FullName, bindingObjectType.FullName), element, property); + throw new FormCompileException($"The binding object named '{bindSourceName}' from the input dictionary is not of expected type '{bindType.FullName}', but '{bindingObjectType.FullName}'", element, property); } } } diff --git a/Composite/C1Console/Forms/ITestAutomationLocatorInformation.cs b/Composite/C1Console/Forms/ITestAutomationLocatorInformation.cs new file mode 100644 index 0000000000..22575d285a --- /dev/null +++ b/Composite/C1Console/Forms/ITestAutomationLocatorInformation.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Composite.C1Console.Forms +{ + public interface ITestAutomationLocatorInformation + { + string TestAutomationLocator { get; } + } +} diff --git a/Composite/C1Console/Forms/StandardProducerMediators/BuildinProducers/BindingsProducer.cs b/Composite/C1Console/Forms/StandardProducerMediators/BuildinProducers/BindingsProducer.cs index 2dbc1e0850..dea4c2113f 100644 --- a/Composite/C1Console/Forms/StandardProducerMediators/BuildinProducers/BindingsProducer.cs +++ b/Composite/C1Console/Forms/StandardProducerMediators/BuildinProducers/BindingsProducer.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; namespace Composite.C1Console.Forms.StandardProducerMediators.BuildinProducers @@ -19,22 +20,12 @@ public List bindings public string GetTypeNameByName(string name) { - foreach (BindingProducer bp in _bindings) - { - if (bp.name == name) return bp.type; - } - - return null; + return _bindings.FirstOrDefault(bp => bp.name == name)?.type; } public bool? GetOptionalValueByName(string name) { - foreach (BindingProducer bp in _bindings) - { - if (bp.name == name) return bp.optional; - } - - return null; + return _bindings.FirstOrDefault(bp => bp.name == name)?.optional; } } } diff --git a/Composite/C1Console/Forms/StandardProducerMediators/BuildinProducers/LayoutProducer.cs b/Composite/C1Console/Forms/StandardProducerMediators/BuildinProducers/LayoutProducer.cs index 76957a010d..647d414ed2 100644 --- a/Composite/C1Console/Forms/StandardProducerMediators/BuildinProducers/LayoutProducer.cs +++ b/Composite/C1Console/Forms/StandardProducerMediators/BuildinProducers/LayoutProducer.cs @@ -1,20 +1,14 @@ namespace Composite.C1Console.Forms.StandardProducerMediators.BuildinProducers { - [ControlValueProperty("UiControl")] + [ControlValueProperty(nameof(UiControl))] internal sealed class LayoutProducer : IBuildinProducer { - private IUiControl _uiControl; - - internal LayoutProducer() { } - - public IUiControl UiControl - { - get { return _uiControl; } - set { _uiControl = value; } - } + public IUiControl UiControl { get; set; } public string label { get; set; } + public string tooltip { get; set; } + public string iconhandle { get; set; } } } diff --git a/Composite/C1Console/Security/EntityToken.cs b/Composite/C1Console/Security/EntityToken.cs index 0fe060227c..eb6a3d8619 100644 --- a/Composite/C1Console/Security/EntityToken.cs +++ b/Composite/C1Console/Security/EntityToken.cs @@ -166,6 +166,18 @@ public override bool Equals(object obj) if (entityToken == null) return false; + if (entityToken.GetVersionHashCode() != GetVersionHashCode()) return false; + + return entityToken.VersionId == this.VersionId && EqualsWithVersionIgnore(entityToken); + } + + /// + public bool EqualsWithVersionIgnore(object obj) + { + EntityToken entityToken = obj as EntityToken; + + if (entityToken == null) return false; + ValidateEntityToken(); @@ -177,6 +189,8 @@ public override bool Equals(object obj) entityToken.GetType() == this.GetType(); } + /// + public virtual string VersionId { get; } = ""; /// @@ -198,6 +212,19 @@ public override int GetHashCode() return this.HashCode; } + /// + public int GetVersionHashCode() + { + if (this.VersionHashCode == 0) + { + this.VersionHashCode = this.VersionId.GetHashCode(); + } + + return this.VersionHashCode; + } + + /// + protected int VersionHashCode { get; set; } /// public override string ToString() diff --git a/Composite/C1Console/Security/PermissionTypeFacade.cs b/Composite/C1Console/Security/PermissionTypeFacade.cs index 9cd2a5deff..3bece4bfcc 100644 --- a/Composite/C1Console/Security/PermissionTypeFacade.cs +++ b/Composite/C1Console/Security/PermissionTypeFacade.cs @@ -29,7 +29,7 @@ public static IEnumerable GetLocallyDefinedUserPermissionTypes(U foreach (UserPermissionDefinition userPermissionDefinition in userPermissionDefinitions) { - if (userPermissionDefinition.EntityToken.Equals(entityToken)) + if (userPermissionDefinition.EntityToken.EqualsWithVersionIgnore(entityToken)) { result.AddRange(userPermissionDefinition.PermissionTypes); } @@ -52,7 +52,7 @@ public static IEnumerable GetLocallyDefinedUserGroupPermissionTy foreach (UserGroupPermissionDefinition userGroupPermissionDefinition in userGroupPermissionDefinitions) { - if (userGroupPermissionDefinition.EntityToken.Equals(entityToken)) + if (userGroupPermissionDefinition.EntityToken.EqualsWithVersionIgnore(entityToken)) { result.AddRange(userGroupPermissionDefinition.PermissionTypes); } @@ -551,7 +551,7 @@ private static IReadOnlyCollection RecursiveUpdateCurrentUserPer } UserPermissionDefinition userPermissionDefinition = userPermissionDefinitions - .Where(f => entityToken.Equals(f.EntityToken)).SingleOrDefaultOrException("More then one UserPermissionDefinition for the same entity token"); + .Where(f => entityToken.EqualsWithVersionIgnore(f.EntityToken)).SingleOrDefaultOrException("More then one UserPermissionDefinition for the same entity token"); var thisPermisstionTypes = new List(); if (userPermissionDefinition != null) @@ -611,7 +611,7 @@ private static IReadOnlyCollection RecursiveUpdateCurrentUserGro return cached; } - IEnumerable selectedUserGroupPermissionDefinitions = userGroupPermissionDefinitions.Where(f => entityToken.Equals(f.EntityToken)); + IEnumerable selectedUserGroupPermissionDefinitions = userGroupPermissionDefinitions.Where(f => entityToken.EqualsWithVersionIgnore(f.EntityToken)); List thisPermisstionTypes = new List(); foreach (UserGroupPermissionDefinition userGroupPermissionDefinition in selectedUserGroupPermissionDefinitions) @@ -664,7 +664,7 @@ private static IReadOnlyCollection RecursiveUpdateCurrentUserGro private static IEnumerable GetInheritedGroupPermissionsTypesRecursivly(EntityToken entityToken, IEnumerable userGroupPermissionDefinitions, List visitedParents = null) { - UserGroupPermissionDefinition selectedUserGroupPermissionDefinition = userGroupPermissionDefinitions.Where(f => entityToken.Equals(f.EntityToken)).SingleOrDefault(); + UserGroupPermissionDefinition selectedUserGroupPermissionDefinition = userGroupPermissionDefinitions.Where(f => entityToken.EqualsWithVersionIgnore(f.EntityToken)).SingleOrDefault(); if (selectedUserGroupPermissionDefinition != null) { if (selectedUserGroupPermissionDefinition.PermissionTypes.Contains(PermissionType.ClearPermissions) == false) @@ -728,8 +728,8 @@ public bool Equals(EntityTokenPair entityTokenPair) { if (entityTokenPair == null) return false; - return this.FirstEntityToken.Equals(entityTokenPair.FirstEntityToken) && - this.SecondEntityToken.Equals(entityTokenPair.SecondEntityToken); + return this.FirstEntityToken.EqualsWithVersionIgnore(entityTokenPair.FirstEntityToken) && + this.SecondEntityToken.EqualsWithVersionIgnore(entityTokenPair.SecondEntityToken); } diff --git a/Composite/C1Console/Workflow/Activities/FormsWorkflow.cs b/Composite/C1Console/Workflow/Activities/FormsWorkflow.cs index 7487006359..5b50d44b18 100644 --- a/Composite/C1Console/Workflow/Activities/FormsWorkflow.cs +++ b/Composite/C1Console/Workflow/Activities/FormsWorkflow.cs @@ -29,7 +29,7 @@ namespace Composite.C1Console.Workflow.Activities { - /// + /// /// /// [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] @@ -70,6 +70,19 @@ public FormsWorkflow() } + /// + protected void InitializeExtensions() + { + CanModifyActivities = true; + + foreach (var extension in FormsWorkflowExtensions.GetExtensions()) + { + extension.Initialize(this); + } + + CanModifyActivities = false; + } + /// protected override void Initialize(IServiceProvider provider) @@ -243,7 +256,7 @@ public T GetBinding(string name) object obj; if (!Bindings.TryGetValue(name, out obj)) { - throw new InvalidOperationException(string.Format("The binding named '{0}' was not found", name)); + throw new InvalidOperationException($"The binding named '{name}' was not found"); } return (T)obj; @@ -315,7 +328,7 @@ public string Payload _workflowActionToken = this.ActionToken as WorkflowActionToken; } - return _workflowActionToken == null ? null : _workflowActionToken.Payload; + return _workflowActionToken?.Payload; } } @@ -331,32 +344,30 @@ public string ExtraPayload _workflowActionToken = this.ActionToken as WorkflowActionToken; } - return _workflowActionToken == null ? null : _workflowActionToken.ExtraPayload; + return _workflowActionToken?.ExtraPayload; } } - internal Guid InstanceId - { - get - { - return _instanceId; - } - } + internal Guid InstanceId => _instanceId; + private static FlowControllerServicesContainer GetFlowControllerServicesContainer() + { + return WorkflowFacade.GetFlowControllerServicesContainer(WorkflowEnvironment.WorkflowInstanceId); + } /// protected void ReportException(Exception ex) { - if (ex == null) throw new ArgumentNullException("ex"); + Verify.ArgumentNotNull(ex, nameof(ex)); - this.ShowMessage(DialogType.Error, "An unfortunate error occurred", string.Format("Sorry, but an error has occurred, preventing the opperation from completing as expected. The error has been documented in details so a technican may follow up on this issue.\n\nThe error message is: {0}", ex.Message)); + this.ShowMessage(DialogType.Error, "An unfortunate error occurred", $"Sorry, but an error has occurred, preventing the opperation from completing as expected. The error has been documented in details so a technican may follow up on this issue.\n\nThe error message is: {ex.Message}"); Log.LogCritical(this.GetType().Name, ex); - FlowControllerServicesContainer container = WorkflowFacade.GetFlowControllerServicesContainer(WorkflowEnvironment.WorkflowInstanceId); + var container = GetFlowControllerServicesContainer(); IManagementConsoleMessageService service = container.GetService(); service.ShowLogEntry(this.GetType(), ex); } @@ -366,7 +377,7 @@ protected void ReportException(Exception ex) /// protected void LogMessage(LogLevel logLevel, string message) { - FlowControllerServicesContainer container = WorkflowFacade.GetFlowControllerServicesContainer(WorkflowEnvironment.WorkflowInstanceId); + var container = GetFlowControllerServicesContainer(); IManagementConsoleMessageService service = container.GetService(); service.ShowLogEntry(this.GetType(), logLevel, message); @@ -396,7 +407,7 @@ protected void LogMessage(LogLevel logLevel, string message) /// protected void ShowMessage(DialogType dialogType, string title, string message) { - FlowControllerServicesContainer container = WorkflowFacade.GetFlowControllerServicesContainer(WorkflowEnvironment.WorkflowInstanceId); + var container = GetFlowControllerServicesContainer(); IManagementConsoleMessageService service = container.GetService(); @@ -415,7 +426,7 @@ protected void ShowMessage(DialogType dialogType, string title, string message) /// protected void SelectElement(EntityToken entityToken) { - FlowControllerServicesContainer container = WorkflowFacade.GetFlowControllerServicesContainer(WorkflowEnvironment.WorkflowInstanceId); + var container = GetFlowControllerServicesContainer(); IManagementConsoleMessageService service = container.GetService(); @@ -427,7 +438,7 @@ protected void SelectElement(EntityToken entityToken) /// protected void RebootConsole() { - FlowControllerServicesContainer container = WorkflowFacade.GetFlowControllerServicesContainer(WorkflowEnvironment.WorkflowInstanceId); + var container = GetFlowControllerServicesContainer(); IManagementConsoleMessageService service = container.GetService(); @@ -439,9 +450,9 @@ protected void RebootConsole() /// protected void ShowFieldMessage(string fieldBindingPath, string message) { - FlowControllerServicesContainer flowControllerServicesContainer = WorkflowFacade.GetFlowControllerServicesContainer(WorkflowEnvironment.WorkflowInstanceId); + var flowControllerServicesContainer = GetFlowControllerServicesContainer(); - IFormFlowRenderingService formFlowRenderingService = flowControllerServicesContainer.GetService(); + var formFlowRenderingService = flowControllerServicesContainer.GetService(); formFlowRenderingService.ShowFieldMessage(fieldBindingPath, StringResourceSystemFacade.ParseString(message)); } @@ -476,25 +487,22 @@ protected void SetSaveStatus(bool succeeded, EntityToken entityToken) /// protected void SetSaveStatus(bool succeeded, string serializedEntityToken) { - SaveWorklowTaskManagerEvent saveWorklowTaskManagerEvent = new SaveWorklowTaskManagerEvent - ( - new WorkflowFlowToken(this.InstanceId), - this.WorkflowInstanceId, - succeeded - ); + var saveWorklowTaskManagerEvent = new SaveWorklowTaskManagerEvent + ( + new WorkflowFlowToken(this.InstanceId), + this.WorkflowInstanceId, + succeeded + ); - FlowControllerServicesContainer container = WorkflowFacade.GetFlowControllerServicesContainer(WorkflowEnvironment.WorkflowInstanceId); - ITaskManagerFlowControllerService service = container.GetService(); + var container = GetFlowControllerServicesContainer(); + var service = container.GetService(); service.OnStatus(saveWorklowTaskManagerEvent); var flowRenderingService = container.GetService(); - if(flowRenderingService != null) - { - flowRenderingService.SetSaveStatus(succeeded); - } + flowRenderingService?.SetSaveStatus(succeeded); - - IManagementConsoleMessageService managementConsoleMessageService = container.GetService(); + + var managementConsoleMessageService = container.GetService(); managementConsoleMessageService.SaveStatus(succeeded); // TO BE REMOVED if (serializedEntityToken != null) @@ -509,7 +517,7 @@ protected void SetSaveStatus(bool succeeded, string serializedEntityToken) /// protected void CloseCurrentView() { - FlowControllerServicesContainer flowControllerServicesContainer = WorkflowFacade.GetFlowControllerServicesContainer(WorkflowEnvironment.WorkflowInstanceId); + var flowControllerServicesContainer = GetFlowControllerServicesContainer(); var managementConsoleMessageService = flowControllerServicesContainer.GetService(); @@ -524,7 +532,7 @@ protected void CloseCurrentView() /// protected void LockTheSystem() { - FlowControllerServicesContainer flowControllerServicesContainer = WorkflowFacade.GetFlowControllerServicesContainer(WorkflowEnvironment.WorkflowInstanceId); + var flowControllerServicesContainer = GetFlowControllerServicesContainer(); IManagementConsoleMessageService managementConsoleMessageService = flowControllerServicesContainer.GetService(); @@ -534,9 +542,9 @@ protected void LockTheSystem() /// - protected void RerenderView() + public void RerenderView() { - FlowControllerServicesContainer flowControllerServicesContainer = WorkflowFacade.GetFlowControllerServicesContainer(WorkflowEnvironment.WorkflowInstanceId); + var flowControllerServicesContainer = GetFlowControllerServicesContainer(); IFormFlowRenderingService formFlowRenderingService = flowControllerServicesContainer.GetService(); formFlowRenderingService.RerenderView(); } @@ -546,8 +554,8 @@ protected void RerenderView() /// protected void CollapseAndRefresh() { - FlowControllerServicesContainer container = WorkflowFacade.GetFlowControllerServicesContainer(WorkflowEnvironment.WorkflowInstanceId); - IManagementConsoleMessageService service = container.GetService(); + var container = GetFlowControllerServicesContainer(); + var service = container.GetService(); service.CollapseAndRefresh(); } @@ -556,7 +564,7 @@ protected void CollapseAndRefresh() /// protected string GetCurrentConsoleId() { - FlowControllerServicesContainer flowControllerServicesContainer = WorkflowFacade.GetFlowControllerServicesContainer(WorkflowEnvironment.WorkflowInstanceId); + var flowControllerServicesContainer = GetFlowControllerServicesContainer(); IManagementConsoleMessageService managementConsoleMessageService = flowControllerServicesContainer.GetService(); @@ -574,9 +582,9 @@ protected IEnumerable GetConsoleIdsOpenedByCurrentUser() /// - protected void ExecuteAction(EntityToken entityToken, ActionToken actionToken) + public void ExecuteAction(EntityToken entityToken, ActionToken actionToken) { - FlowControllerServicesContainer flowControllerServicesContainer = WorkflowFacade.GetFlowControllerServicesContainer(WorkflowEnvironment.WorkflowInstanceId); + var flowControllerServicesContainer = GetFlowControllerServicesContainer(); IActionExecutionService actionExecutionService = flowControllerServicesContainer.GetService(); @@ -587,7 +595,7 @@ protected void ExecuteAction(EntityToken entityToken, ActionToken actionToken) /// - protected void ExecuteWorklow(EntityToken entityToken, Type workflowType) + public void ExecuteWorklow(EntityToken entityToken, Type workflowType) { ExecuteAction(entityToken, new WorkflowActionToken(workflowType)); } @@ -597,6 +605,8 @@ protected void ExecuteWorklow(EntityToken entityToken, Type workflowType) /// protected void DeliverFormData(string containerLabel, IFlowUiContainerType containerType, string formDefinition, Dictionary bindings, Dictionary> bindingsValidationRules) { + OnDeliverFormData(bindings, bindingsValidationRules); + ExternalDataExchangeService externalDataExchangeService = WorkflowFacade.WorkflowRuntime.GetService(); IFormsWorkflowActivityService formsWorkflowActivityService = externalDataExchangeService.GetService(typeof(IFormsWorkflowActivityService)) as IFormsWorkflowActivityService; @@ -609,21 +619,43 @@ protected void DeliverFormData(string containerLabel, IFlowUiContainerType conta /// protected void DeliverFormData(string containerLabel, IFlowUiContainerType containerType, IFormMarkupProvider formMarkupProvider, Dictionary bindings, Dictionary> bindingsValidationRules) { - ExternalDataExchangeService externalDataExchangeService = WorkflowFacade.WorkflowRuntime.GetService(); + OnDeliverFormData(bindings, bindingsValidationRules); - IFormsWorkflowActivityService formsWorkflowActivityService = externalDataExchangeService.GetService(typeof(IFormsWorkflowActivityService)) as IFormsWorkflowActivityService; + var externalDataExchangeService = WorkflowFacade.WorkflowRuntime.GetService(); + + var formsWorkflowActivityService = externalDataExchangeService.GetService(typeof(IFormsWorkflowActivityService)) as IFormsWorkflowActivityService; formsWorkflowActivityService.DeliverFormData(WorkflowEnvironment.WorkflowInstanceId, containerLabel, containerType, formMarkupProvider, bindings, bindingsValidationRules); } + + private void OnDeliverFormData(Dictionary bindings, Dictionary> bindingsValidationRules) + { + var parameters = new OnDeliverFormDataParameters() + { + Bindings = bindings, + BindingsValidationRules = bindingsValidationRules + }; + + foreach (var extension in FormsWorkflowExtensions.GetExtensions()) + { + extension.OnDeliverFormData(this, parameters); + } + } + + + + + /// /// Adds the cms:layout elements Form Definition to the UI toolbar. /// /// String containing a valid Form Definition markup document - protected void SetCustomToolbarDefinition(string customToolbarDefinition) + public void SetCustomToolbarDefinition(string customToolbarDefinition) { ExternalDataExchangeService externalDataExchangeService = WorkflowFacade.WorkflowRuntime.GetService(); + IFormsWorkflowActivityService formsWorkflowActivityService = externalDataExchangeService.GetService(typeof(IFormsWorkflowActivityService)) as IFormsWorkflowActivityService; formsWorkflowActivityService.DeliverCustomToolbarDefinition(WorkflowEnvironment.WorkflowInstanceId, customToolbarDefinition); } @@ -637,7 +669,7 @@ protected void SetCustomToolbarDefinition(string customToolbarDefinition) protected void SetCustomToolbarDefinition(IFormMarkupProvider customToolbarMarkupProvider) { ExternalDataExchangeService externalDataExchangeService = WorkflowFacade.WorkflowRuntime.GetService(); - IFormsWorkflowActivityService formsWorkflowActivityService = externalDataExchangeService.GetService(typeof(IFormsWorkflowActivityService)) as IFormsWorkflowActivityService; + var formsWorkflowActivityService = externalDataExchangeService.GetService(typeof(IFormsWorkflowActivityService)) as IFormsWorkflowActivityService; formsWorkflowActivityService.DeliverCustomToolbarDefinition(WorkflowEnvironment.WorkflowInstanceId, customToolbarMarkupProvider); } @@ -839,7 +871,7 @@ protected bool BindAndValidate(DataTypeDescriptorFormsHelper helper, IData data) && (fieldValue as string) == string.Empty && !helper.BindingIsOptional(bindingName)) { - this.ShowFieldMessage(bindingName, StringResourceSystemFacade.GetString("Composite.Management", "Validation.RequiredField")); + this.ShowFieldMessage(bindingName, LocalizationFiles.Composite_Management.Validation_RequiredField); isValid = false; } diff --git a/Composite/C1Console/Workflow/FormsWorkflowExtensions.cs b/Composite/C1Console/Workflow/FormsWorkflowExtensions.cs new file mode 100644 index 0000000000..6852e1f13b --- /dev/null +++ b/Composite/C1Console/Workflow/FormsWorkflowExtensions.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace Composite.C1Console.Workflow +{ + public static class FormsWorkflowExtensions + { + private static readonly List _extensions = new List(); + + public static void Register(IFormsWorkflowExtension extension) => _extensions.Add(extension); + + internal static ICollection GetExtensions() => _extensions; + } +} diff --git a/Composite/C1Console/Workflow/Foundation/FormData.cs b/Composite/C1Console/Workflow/Foundation/FormData.cs index 7b284352c1..5ed1b7f6ad 100644 --- a/Composite/C1Console/Workflow/Foundation/FormData.cs +++ b/Composite/C1Console/Workflow/Foundation/FormData.cs @@ -130,13 +130,14 @@ public XElement Serialize() XElement excludedEventsElement = xmlSerializer.Serialize(typeof(List), ExcludedEvents); - XElement formDataElement = new XElement("FormData"); - formDataElement.Add(containerLabelElement); - formDataElement.Add(formDefinitionElement); - formDataElement.Add(customToolbarDefinitionElement); - formDataElement.Add(new XElement("ContainerType", containerTypeElement)); - formDataElement.Add(new XElement("Bindings", bindingsElement)); - formDataElement.Add(new XElement("BindingsValidationRules", bindingsValidationRulesElement)); + var formDataElement = new XElement("FormData", + containerLabelElement, + formDefinitionElement, + customToolbarDefinitionElement, + new XElement("ContainerType", containerTypeElement), + new XElement("Bindings", bindingsElement), + new XElement("BindingsValidationRules", bindingsValidationRulesElement) + ); if (excludedEventsElement != null) formDataElement.Add(new XElement("ExcludedEvents", excludedEventsElement)); if (this.EventHandleFilterType != null) diff --git a/Composite/C1Console/Workflow/IFormsWorkflowExtension.cs b/Composite/C1Console/Workflow/IFormsWorkflowExtension.cs new file mode 100644 index 0000000000..f73c701e58 --- /dev/null +++ b/Composite/C1Console/Workflow/IFormsWorkflowExtension.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using Composite.C1Console.Workflow.Activities; +using Composite.Data.Validation.ClientValidationRules; + +namespace Composite.C1Console.Workflow +{ + /// + public class OnDeliverFormDataParameters + { + /// + public Dictionary Bindings { get; set; } + + /// + public Dictionary> BindingsValidationRules { get; set; } + } + + /// + /// An interface for forms workflow extensions + /// + public interface IFormsWorkflowExtension + { + /// + /// In implementation custom workflow activities can be added. + /// + /// The workflow instance. + void Initialize(FormsWorkflow workflow); + + /// + /// Handles form data delivery event + /// + /// The workflow instance. + /// The parameters. + void OnDeliverFormData(FormsWorkflow workflow, OnDeliverFormDataParameters parameters); + } +} diff --git a/Composite/C1Console/Workflow/WorkflowFlowController.cs b/Composite/C1Console/Workflow/WorkflowFlowController.cs index ac65069b9a..a99d16c9d9 100644 --- a/Composite/C1Console/Workflow/WorkflowFlowController.cs +++ b/Composite/C1Console/Workflow/WorkflowFlowController.cs @@ -117,7 +117,7 @@ private static void AddEventHandles(FormFlowUiDefinition formFlowUiDefinition, G foreach (string eventName in eventNames) { - if (formData != null && formData.ExcludedEvents != null && formData.ExcludedEvents.Contains(eventName)) continue; + if (formData?.ExcludedEvents != null && formData.ExcludedEvents.Contains(eventName)) continue; switch (eventName) { @@ -172,10 +172,7 @@ private static void AddEventHandles(FormFlowUiDefinition formFlowUiDefinition, G } IEventHandleFilter eventHandlerFilter = WorkflowFacade.GetEventHandleFilter(instanceId); - if (eventHandlerFilter != null) - { - eventHandlerFilter.Filter(formFlowUiDefinition.EventHandlers); - } + eventHandlerFilter?.Filter(formFlowUiDefinition.EventHandlers); } diff --git a/Composite/Composite.csproj b/Composite/Composite.csproj index 2de3d759bc..37fe2b4819 100644 --- a/Composite/Composite.csproj +++ b/Composite/Composite.csproj @@ -168,9 +168,21 @@ + - + + + + + + + + + + + + @@ -2510,16 +2522,16 @@ - copy "$(TargetPath)" "$(ProjectDir)..\bin\" copy "$(TargetPath)" "$(ProjectDir)..\Website\bin\" - \ No newline at end of file + diff --git a/Composite/Core/Configuration/BuildinPlugins/GlobalSettingsProvider/BuildinGlobalSettingsProvider.cs b/Composite/Core/Configuration/BuildinPlugins/GlobalSettingsProvider/BuildinGlobalSettingsProvider.cs index 2506014228..f2d3a02cfe 100644 --- a/Composite/Core/Configuration/BuildinPlugins/GlobalSettingsProvider/BuildinGlobalSettingsProvider.cs +++ b/Composite/Core/Configuration/BuildinPlugins/GlobalSettingsProvider/BuildinGlobalSettingsProvider.cs @@ -12,7 +12,7 @@ internal sealed class BuildinGlobalSettingsProvider : IGlobalSettingsProvider private string _applicationShortName = "C1"; private string _brandedVersionAssemblySource = "Composite"; private string _configurationDirectory = "~"; - private string _generatedAssembliesDirectory = "~"; + private string _generatedAssembliesDirectory = "~/GeneratedAssemblies"; private string _serializedWorkflowsDirectory = "~"; private string _appCodeDirectory = "App_Code"; private string _binDirectory = "~"; @@ -36,28 +36,14 @@ internal sealed class BuildinGlobalSettingsProvider : IGlobalSettingsProvider private bool _functionPreviewEnabled = false; private TimeZoneInfo _timezone = TimeZoneInfo.Local; - public string ApplicationName - { - get { return _applicationName; } - } + public string ApplicationName => _applicationName; - public string ApplicationShortName - { - get { return _applicationShortName; } - } + public string ApplicationShortName => _applicationShortName; - public string BrandedVersionAssemblySource - { - get { return _brandedVersionAssemblySource; } - } - - - public string DefaultCultureName - { - get { return Thread.CurrentThread.CurrentCulture.Name; } - } + public string BrandedVersionAssemblySource => _brandedVersionAssemblySource; + public string DefaultCultureName => Thread.CurrentThread.CurrentCulture.Name; public string ConfigurationDirectory @@ -70,14 +56,7 @@ public string ConfigurationDirectory - public string GeneratedAssembliesDirectory - { - get - { - return string.Format("{0}/{1}", _generatedAssembliesDirectory, Guid.NewGuid()); - } - } - + public string GeneratedAssembliesDirectory => _generatedAssembliesDirectory; public string SerializedWorkflowsDirectory @@ -90,183 +69,70 @@ public string SerializedWorkflowsDirectory } - public string AppCodeDirectory - { - get - { - return _appCodeDirectory; - } - } - - - public string BinDirectory - { - get - { - return _binDirectory; - } - } - - - - public string TempDirectory - { - get - { - return _tempDirectory; - } - } - - - - public string CacheDirectory - { - get { return _cacheDirectory; } - } - - + public string AppCodeDirectory => _appCodeDirectory; - public string PackageDirectory - { - get - { - return _packageDirectory; - } - } + public string BinDirectory => _binDirectory; - public string AutoPackageInstallDirectory - { - get - { - return _autoPackageInstallDirectory; - } - } + public string TempDirectory => _tempDirectory; + public string CacheDirectory => _cacheDirectory; - public string TreeDefinitionsDirectory - { - get - { - return _treeDefinitionsDirectory; - } - } + public string PackageDirectory => _packageDirectory; - public string PageTemplateFeaturesDirectory - { - get - { - return _pageTemplateFeaturesDirectory; - } - } + public string AutoPackageInstallDirectory => _autoPackageInstallDirectory; + public string TreeDefinitionsDirectory => _treeDefinitionsDirectory; - public string DataMetaDataDirectory - { - get - { - return _dataMetaDataDirectory; - } - } + public string PageTemplateFeaturesDirectory => _pageTemplateFeaturesDirectory; - public string InlineCSharpFunctionDirectory - { - get - { - return _inlineCSharpFunctionDirectory; - } - } + public string DataMetaDataDirectory => _dataMetaDataDirectory; - public string PackageLicenseDirectory - { - get - { - return _packageLicenseDirectory; - } - } + public string InlineCSharpFunctionDirectory => _inlineCSharpFunctionDirectory; - public IResourceCacheSettings ResourceCacheSettings - { - get { return _resourceCacheSettings; } - } + public string PackageLicenseDirectory => _packageLicenseDirectory; - public IEnumerable NonProbableAssemblyNames - { - get { return _nonProbableAssemblyNames; } - } + public IResourceCacheSettings ResourceCacheSettings => _resourceCacheSettings; + public IEnumerable NonProbableAssemblyNames => _nonProbableAssemblyNames; - public int ConsoleMessageQueueItemSecondToLive - { - get { return _consoleMessageQueueSecondToLive; } - } + public int ConsoleMessageQueueItemSecondToLive => _consoleMessageQueueSecondToLive; - public bool EnableDataTypesAutoUpdate - { - get { return _enableDataTypesAutoUpdate; } - } + public bool EnableDataTypesAutoUpdate => _enableDataTypesAutoUpdate; - public bool BroadcastConsoleElementChanges - { - get { return _broadcastConsoleElementChanges; } - } + public bool BroadcastConsoleElementChanges => _broadcastConsoleElementChanges; - public string AutoCreatedAdministratorUserName - { - get { return null; } - } + public string AutoCreatedAdministratorUserName => null; - public string SerializedConsoleMessagesDirectory - { - get - { - return string.Format("{0}/{1}", _serializedWorkflowsDirectory, Guid.NewGuid()); - } - } + public string SerializedConsoleMessagesDirectory => $"{_serializedWorkflowsDirectory}/{Guid.NewGuid()}"; - public string WorkflowTimeout - { - get { return "7.00:00:00"; } - } + public string WorkflowTimeout => "7.00:00:00"; - public string ConsoleTimeout - { - get { return "00:01:00"; } - } + public string ConsoleTimeout => "00:01:00"; - public bool OnlyTranslateWhenApproved { - get { return false; } } + public bool OnlyTranslateWhenApproved => false; - public ICachingSettings Caching - { - get { return _cachingSettings; } - } + public ICachingSettings Caching => _cachingSettings; - public int ImageQuality - { - get - { - return 80; - } - } + public int ImageQuality => 80; public bool PrettifyPublicMarkup => _prettifyPublicMarkup; diff --git a/Composite/Core/Extensions/DateTimeExtensionMethods.cs b/Composite/Core/Extensions/DateTimeExtensionMethods.cs new file mode 100644 index 0000000000..6227af2f06 --- /dev/null +++ b/Composite/Core/Extensions/DateTimeExtensionMethods.cs @@ -0,0 +1,72 @@ +using System; +using Composite.Core.Configuration; +using Composite.Core.ResourceSystem; + + +namespace Composite.Core.Extensions +{ + /// + /// + /// + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public static class DateTimeExtensionMethods + { + + /// + private static string TimeZoneAbbreviatedName() + { + return StringResourceSystemFacade.GetString("Composite.Plugins.TimezoneAbbreviations", + "TimezoneAbbreviations." + GlobalSettingsFacade.TimeZone.Id); + } + + + /// + public static string ToTimeZoneDateTimeString(this DateTime? dateTime) + { + return dateTime?.ToTimeZoneDateTimeString(); + } + + /// + public static string ToTimeZoneDateTimeString(this DateTime dateTime) + { + + var convertedToShow = dateTime.ToTimeZone(); + + return + $"{convertedToShow.ToShortDateString()} {convertedToShow.ToShortTimeString()} {TimeZoneAbbreviatedName()}"; + } + + /// + public static string ToTimeZoneDateString(this DateTime? dateTime) + { + return dateTime?.ToTimeZoneDateString(); + } + + /// + public static string ToTimeZoneDateString(this DateTime dateTime) + { + var convertedToShow = dateTime.ToTimeZone(); + + return convertedToShow.ToShortDateString(); + } + + /// + public static DateTime FromTimeZoneToUtc(this DateTime dateTime) + { + return TimeZoneInfo.ConvertTime(dateTime, GlobalSettingsFacade.TimeZone, TimeZoneInfo.Utc); + } + + /// + public static DateTime ToTimeZone(this DateTime dateTime) + { + return TimeZoneInfo.ConvertTime(dateTime, GlobalSettingsFacade.TimeZone); + } + + /// + public static bool TryParseInTimeZone(string s, out DateTime result) + { + return DateTime.TryParse(s.Replace(TimeZoneAbbreviatedName(), ""), out result); + } + + } +} diff --git a/Composite/Core/Extensions/IQueryableExtensionMethods.cs b/Composite/Core/Extensions/IQueryableExtensionMethods.cs index 1d772f5009..64a18b7853 100644 --- a/Composite/Core/Extensions/IQueryableExtensionMethods.cs +++ b/Composite/Core/Extensions/IQueryableExtensionMethods.cs @@ -4,6 +4,7 @@ using System.Reflection; using Composite.Core.Types; using Composite.Data; +using Composite.Data.Caching; using Composite.Data.Foundation; namespace Composite.Core.Extensions @@ -46,7 +47,12 @@ public static bool IsEnumerableQuery(this IQueryable query) return (query as DataFacadeQueryable).IsEnumerableQuery; } - return query.GetType().GetGenericTypeDefinition().FullName.StartsWith("System.Linq.EnumerableQuery"); + if (query is CachingQueryable) + { + return true; + } + + return query.GetType().GetGenericTypeDefinition() == typeof(EnumerableQuery<>); } diff --git a/Composite/Core/Extensions/PageUrlDataExtensionMethods.cs b/Composite/Core/Extensions/PageUrlDataExtensionMethods.cs index e52c87a459..315676a69d 100644 --- a/Composite/Core/Extensions/PageUrlDataExtensionMethods.cs +++ b/Composite/Core/Extensions/PageUrlDataExtensionMethods.cs @@ -14,10 +14,15 @@ public static class PageUrlDataExtensionMethods /// public static IPage GetPage(this PageUrlData pageUrlData) { - Verify.ArgumentNotNull(pageUrlData, "pageUrlData"); + Verify.ArgumentNotNull(pageUrlData, nameof(pageUrlData)); using (new DataScope(pageUrlData.PublicationScope, pageUrlData.LocalizationScope)) { + if (pageUrlData.VersionId != null) + { + return PageManager.GetPageById(pageUrlData.PageId, pageUrlData.VersionId.Value); + } + return PageManager.GetPageById(pageUrlData.PageId); } } diff --git a/Composite/Core/IO/Foundation/PluginFacades/IOProviderPluginFacade.cs b/Composite/Core/IO/Foundation/PluginFacades/IOProviderPluginFacade.cs index faffd99190..ac84d2d363 100644 --- a/Composite/Core/IO/Foundation/PluginFacades/IOProviderPluginFacade.cs +++ b/Composite/Core/IO/Foundation/PluginFacades/IOProviderPluginFacade.cs @@ -5,6 +5,7 @@ using Composite.C1Console.Events; using Composite.Core.IO.Plugins.IOProvider; using Composite.Core.IO.Plugins.IOProvider.Runtime; +using Composite.Plugins.IO.IOProviders.LocalIOProvider; namespace Composite.Core.IO.Foundation.PluginFacades @@ -13,7 +14,7 @@ internal static class IOProviderPluginFacade { private static IOProviderFactory _factory; private static IIOProvider _ioProvider; - private static object _lock = new object(); + private static readonly object _lock = new object(); static IOProviderPluginFacade() @@ -130,11 +131,16 @@ public static IC1Configuration CreateConfiguration(string path) private static IIOProvider GetIOProvider() { - if (_factory == null || _ioProvider == null) + if (_ioProvider == null) { lock (_lock) { - if (_factory == null || _ioProvider == null) + if (RuntimeInformation.IsUnittest) + { + return _ioProvider = new LocalIOProvider(); + } + + if (_ioProvider == null) { try { diff --git a/Composite/Core/Implementation/DataConnectionImplementation.cs b/Composite/Core/Implementation/DataConnectionImplementation.cs index aa41c0d1c8..3a98273486 100644 --- a/Composite/Core/Implementation/DataConnectionImplementation.cs +++ b/Composite/Core/Implementation/DataConnectionImplementation.cs @@ -1,5 +1,8 @@ -using System; +//#define ConnectionLeakCheck + +using System; using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; using System.Linq; using Composite.Core.Threading; @@ -13,10 +16,14 @@ namespace Composite.Core.Implementation /// public class DataConnectionImplementation : DataConnectionBase, IDisposable { +#if ConnectionLeakCheck + private string _allocationCallStack; +#endif + private IDisposable _threadDataManager; private readonly DataScope _dataScope; - + internal DataScope DataScope => _dataScope; /// /// Stateless constructor. This is used when implementations of static methods needs to be called /// Used when New and AllLocales are called @@ -44,14 +51,18 @@ public DataConnectionImplementation(PublicationScope scope, CultureInfo locale) private void InitializeThreadData() { _threadDataManager = ThreadDataManager.EnsureInitialize(); - } - /// - /// Documentation pending - /// - /// - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get", Justification = "This is what we want")] +#if ConnectionLeakCheck + _allocationCallStack = new StackTrace().ToString(); +#endif + } + + /// + /// Documentation pending + /// + /// + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get", Justification = "This is what we want")] public virtual IQueryable Get() where TData : class, IData { @@ -178,39 +189,19 @@ public virtual TData New() /// /// Documentation pending /// - public virtual PublicationScope CurrentPublicationScope - { - get - { - return this.PublicationScope; - } - } - + public virtual PublicationScope CurrentPublicationScope => this.PublicationScope; /// /// Documentation pending /// - public virtual CultureInfo CurrentLocale - { - get - { - return this.Locale; - } - } + public virtual CultureInfo CurrentLocale => this.Locale; /// /// Documentation pending /// - public virtual IEnumerable AllLocales - { - get - { - return DataLocalizationFacade.ActiveLocalizationCultures; - } - } - + public virtual IEnumerable AllLocales => DataLocalizationFacade.ActiveLocalizationCultures; /// @@ -227,6 +218,10 @@ public void Dispose() /// ~DataConnectionImplementation() { +#if ConnectionLeakCheck + Log.LogError(nameof(DataConnection), "Not disposed data connection allocated at: " + _allocationCallStack); +#endif + Dispose(false); } diff --git a/Composite/Core/Implementation/ImplementationFactory.cs b/Composite/Core/Implementation/ImplementationFactory.cs index 9d2d9b2f2f..8b6758de5e 100644 --- a/Composite/Core/Implementation/ImplementationFactory.cs +++ b/Composite/Core/Implementation/ImplementationFactory.cs @@ -2,8 +2,7 @@ using Composite.Data; using System.IO; using System.Text; - - +using System; namespace Composite.Core.Implementation { /// @@ -46,9 +45,12 @@ public virtual DataConnectionImplementation StatelessDataConnection { return new DataConnectionImplementation(); } - } - + } + internal object ResolveService(Type t) + { + return DataServiceScopeManager.GetService(t); + } /// /// Documentation pending diff --git a/Composite/Core/PackageSystem/PackageFragmentInstallers/DataPackageFragmentInstaller.cs b/Composite/Core/PackageSystem/PackageFragmentInstallers/DataPackageFragmentInstaller.cs index 2c0dcaba06..27cb5566ad 100644 --- a/Composite/Core/PackageSystem/PackageFragmentInstallers/DataPackageFragmentInstaller.cs +++ b/Composite/Core/PackageSystem/PackageFragmentInstallers/DataPackageFragmentInstaller.cs @@ -33,6 +33,8 @@ public sealed class DataPackageFragmentInstaller : BasePackageFragmentInstaller private Dictionary _dataKeysToBeInstalled; private Dictionary>> _missingDataReferences; + private static Dictionary _pageVersionIds = new Dictionary(); + /// public override IEnumerable Validate() { @@ -154,7 +156,7 @@ private static Type GetInstalledVersionOfPendingType(Type interfaceType, IData d } - private static XElement AddData(DataType dataType, CultureInfo cultureInfo) + private XElement AddData(DataType dataType, CultureInfo cultureInfo) { XElement datasElement = new XElement("Datas"); @@ -165,11 +167,13 @@ private static XElement AddData(DataType dataType, CultureInfo cultureInfo) foreach (XElement addElement in dataType.Dataset) { - IData data = DataFacade.BuildNew(dataType.InterfaceType); + var interfaceType = dataType.InterfaceType; + + IData data = DataFacade.BuildNew(interfaceType); if (!dataType.InterfaceType.IsInstanceOfType(data)) { - dataType.InterfaceType = GetInstalledVersionOfPendingType(dataType.InterfaceType, data); + dataType.InterfaceType = GetInstalledVersionOfPendingType(interfaceType, data); } @@ -177,7 +181,7 @@ private static XElement AddData(DataType dataType, CultureInfo cultureInfo) if (dataType.AllowOverwrite || dataType.OnlyUpdate) { - IData existingData = DataFacade.TryGetDataByUniqueKey(dataType.InterfaceType, dataKey); + IData existingData = DataFacade.TryGetDataByUniqueKey(interfaceType, dataKey); if (data != null) { @@ -196,7 +200,12 @@ private static XElement AddData(DataType dataType, CultureInfo cultureInfo) ILocalizedControlled localizedControlled = data as ILocalizedControlled; if (localizedControlled != null) { - localizedControlled.SourceCultureName = LocalizationScopeManager.MapByType(dataType.InterfaceType).Name; + localizedControlled.SourceCultureName = LocalizationScopeManager.MapByType(interfaceType).Name; + } + + if (data is IVersioned) + { + UpdateVersionId((IVersioned)data); } DataFacade.AddNew(data, false, true, false); // Ignore validation, this should have been done in the validation face @@ -221,6 +230,54 @@ private static XElement AddData(DataType dataType, CultureInfo cultureInfo) return datasElement; } + + private void UpdateVersionId(IVersioned data) + { + if (data.VersionId != Guid.Empty) + { + return; + } + + if (data is IPage) + { + var page = (IPage)data; + + Guid versionId; + + if (_pageVersionIds.TryGetValue(page.Id, out versionId)) + { + page.VersionId = versionId; + } + else + { + page.VersionId = Guid.NewGuid(); + _pageVersionIds[page.Id] = page.VersionId; + } + } + + else if (data is IPagePlaceholderContent) + { + Guid pageId = ((IPagePlaceholderContent)data).PageId; + Guid versionId; + + if (_pageVersionIds.TryGetValue(pageId, out versionId)) + { + data.VersionId = versionId; + } + } + else if (data is IPageData) + { + Guid pageId = ((IPageData)data).PageId; + Guid versionId; + + if (_pageVersionIds.TryGetValue(pageId, out versionId)) + { + data.VersionId = versionId; + } + } + } + + private static DataKeyPropertyCollection CopyFieldValues(DataType dataType, IData data, XElement addElement) { var dataKeyPropertyCollection = new DataKeyPropertyCollection(); @@ -413,16 +470,17 @@ private void ValidateNonDynamicAddedType(DataType dataType) DataTypeDescriptor dataTypeDescriptor = DynamicTypeManager.BuildNewDataTypeDescriptor(dataType.InterfaceType); - List requiredPropertyNames = - (from dfd in dataTypeDescriptor.Fields - where !dfd.IsNullable - select dfd.Name).ToList(); - List nonRequiredPropertyNames = + bool isVersionedDataType = typeof (IVersioned).IsAssignableFrom(dataType.InterfaceType); + + var requiredPropertyNames = (from dfd in dataTypeDescriptor.Fields - where dfd.IsNullable + where !dfd.IsNullable && !(isVersionedDataType && dfd.Name == nameof(IVersioned.VersionId)) // Compatibility fix select dfd.Name).ToList(); + var nonRequiredPropertyNames = dataTypeDescriptor.Fields.Select(f => f.Name) + .Except(requiredPropertyNames).ToList(); + foreach (XElement addElement in dataType.Dataset) { @@ -596,6 +654,7 @@ private static bool IsObsoleteField(DataType dataType, string fieldName) return typeof(ILocalizedControlled).IsAssignableFrom(dataType.InterfaceType) && fieldName == "CultureName"; } + private static Dictionary GetDataTypeProperties(Type type) { return type.GetPropertiesRecursively().Where(property => !IsObsoleteProperty(property)).ToDictionary(prop => prop.Name); diff --git a/Composite/Core/Parallelization/ParallelFacade.cs b/Composite/Core/Parallelization/ParallelFacade.cs index ec21e937f2..e4b9e8159a 100644 --- a/Composite/Core/Parallelization/ParallelFacade.cs +++ b/Composite/Core/Parallelization/ParallelFacade.cs @@ -216,6 +216,8 @@ public void WrapperAction(TSource source) languageScopePushed = true; } + DataServiceScopeManager.EnterThreadLocal(); + HttpContext.Current = _parentThreadHttpContext; currentThread.CurrentCulture = _parentThreadCulture; @@ -259,6 +261,7 @@ public void WrapperAction(TSource source) DataScopeManager.ExitThreadLocal(); LocalizationScopeManager.ExitThreadLocal(); + DataServiceScopeManager.ExitThreadLocal(); } } } diff --git a/Composite/Core/ResourceSystem/LocalizationFiles.cs b/Composite/Core/ResourceSystem/LocalizationFiles.cs index fa64009cd3..8a650b7b9a 100644 --- a/Composite/Core/ResourceSystem/LocalizationFiles.cs +++ b/Composite/Core/ResourceSystem/LocalizationFiles.cs @@ -338,15 +338,15 @@ public static class Composite_C1Console_Users { public static string ChangeOwnCultureWorkflow_ElementActionLabel=>T("ChangeOwnCultureWorkflow.ElementActionLabel"); ///"Set the C1 Console language and formatting of numbers, times and dates" public static string ChangeOwnCultureWorkflow_ElementActionToolTip=>T("ChangeOwnCultureWorkflow.ElementActionToolTip"); -///"Regional Settings and Language" +///"Profile Settings" public static string ChangeOwnCultureWorkflow_Dialog_Label=>T("ChangeOwnCultureWorkflow.Dialog.Label"); ///"Display Preferences" public static string ChangeOwnCultureWorkflow_Dialog_CultureSelector_Label=>T("ChangeOwnCultureWorkflow.Dialog.CultureSelector.Label"); -///"Select from the list of options to update how time, date, and number formats are displayed within the console." +///"Display for time, date, and number formats within the console" public static string ChangeOwnCultureWorkflow_Dialog_CultureSelector_Help=>T("ChangeOwnCultureWorkflow.Dialog.CultureSelector.Help"); ///"Console Language Preferences" public static string ChangeOwnCultureWorkflow_Dialog_C1ConsoleLanguageSelector_Label=>T("ChangeOwnCultureWorkflow.Dialog.C1ConsoleLanguageSelector.Label"); -///"Select the language to be used for labels, help texts, dialogs etc. The available options here are limited to languages installed. You may install more languages via the Package system, see Composite.Localization." +///"Language displayed within your console for labels, help texts, dialogs, etc. The available options are limited to language packages installed. See Composite.Localization packages for more language options." public static string ChangeOwnCultureWorkflow_Dialog_C1ConsoleLanguageSelector_Help=>T("ChangeOwnCultureWorkflow.Dialog.C1ConsoleLanguageSelector.Help"); ///"Change application language" public static string ChangeOwnCultureWorkflow_Dialog_Confirm_Title=>T("ChangeOwnCultureWorkflow.Dialog.Confirm.Title"); @@ -1149,6 +1149,8 @@ public static class Composite_Management { public static string Website_Folder_SelectDialog_Title=>T("Website.Folder.SelectDialog.Title"); ///"Draft" public static string PublishingStatus_draft=>T("PublishingStatus.draft"); +///"Sent to Draft" +public static string PublishingStatus_sentToDraft=>T("PublishingStatus.sentToDraft"); ///"Awaiting Approval" public static string PublishingStatus_awaitingApproval=>T("PublishingStatus.awaitingApproval"); ///"Awaiting Publication" @@ -1179,13 +1181,13 @@ public static class Composite_Management { public static string Website_Forms_Administrative_EditUserStep1_GroupHelp=>T("Website.Forms.Administrative.EditUserStep1.GroupHelp"); ///"C1 Console Localization" public static string Website_Forms_Administrative_EditUserStep1_LabelLocalizationFieldGroup=>T("Website.Forms.Administrative.EditUserStep1.LabelLocalizationFieldGroup"); -///"Regional settings" +///"Display Preferences" public static string Website_Forms_Administrative_EditUserStep1_CultureLabel=>T("Website.Forms.Administrative.EditUserStep1.CultureLabel"); -///"To change the way numbers, dates, and hours are displayed, select an entry from the list." +///"Display for time, date, and number formats within the console" public static string Website_Forms_Administrative_EditUserStep1_CultureHelp=>T("Website.Forms.Administrative.EditUserStep1.CultureHelp"); -///"C1 Console Language" +///"Console Language Preferences" public static string Website_Forms_Administrative_EditUserStep1_C1ConsoleLanguageLabel=>T("Website.Forms.Administrative.EditUserStep1.C1ConsoleLanguageLabel"); -///"Select the language to be used for labels, help texts, dialogs etc. The available options here are limited to languages installed. You may install more languages via the Package system, see Composite.Localization." +///"Language displayed within your console for labels, help texts, dialogs, etc. The available options are limited to language packages installed. See Composite.Localization packages for more language options." public static string Website_Forms_Administrative_EditUserStep1_C1ConsoleLanguageHelp=>T("Website.Forms.Administrative.EditUserStep1.C1ConsoleLanguageHelp"); ///"Perspectives" public static string Website_Forms_Administrative_EditUserStep1_ActivePerspectiveFieldLabel=>T("Website.Forms.Administrative.EditUserStep1.ActivePerspectiveFieldLabel"); @@ -1285,13 +1287,13 @@ public static class Composite_Management { public static string Website_Forms_Administrative_AddNewUserStep1_GroupLabel=>T("Website.Forms.Administrative.AddNewUserStep1.GroupLabel"); ///"If you enter a folder name that does not already exist a new folder will be created." public static string Website_Forms_Administrative_AddNewUserStep1_GroupHelp=>T("Website.Forms.Administrative.AddNewUserStep1.GroupHelp"); -///"Regional settings" +///"Display Preferences" public static string Website_Forms_Administrative_AddNewUserStep1_CultureLabel=>T("Website.Forms.Administrative.AddNewUserStep1.CultureLabel"); -///"To change the way numbers, dates, and hours are displayed, select an entry from the list." +///"Display for time, date, and number formats within the console" public static string Website_Forms_Administrative_AddNewUserStep1_CultureHelp=>T("Website.Forms.Administrative.AddNewUserStep1.CultureHelp"); -///"C1 Console Language" +///"Console Language Preferences" public static string Website_Forms_Administrative_AddNewUserStep1_C1ConsoleLanguageLabel=>T("Website.Forms.Administrative.AddNewUserStep1.C1ConsoleLanguageLabel"); -///"Select the language to be used for labels, help texts, dialogs etc. The available options here are limited to languages installed. You may install more languages via the Package system, see Composite.Localization." +///"Language displayed within your console for labels, help texts, dialogs, etc. The available options are limited to language packages installed. See Composite.Localization packages for more language options." public static string Website_Forms_Administrative_AddNewUserStep1_C1ConsoleLanguageHelp=>T("Website.Forms.Administrative.AddNewUserStep1.C1ConsoleLanguageHelp"); ///"A language is required" public static string UserElementProvider_MissingActiveLanguageTitle=>T("UserElementProvider.MissingActiveLanguageTitle"); @@ -2453,6 +2455,8 @@ public static class Composite_Management { public static string Browser_Label=>T("Browser.Label"); ///"Browse unpublished pages" public static string Browser_ToolTip=>T("Browser.ToolTip"); +///"Original" +public static string DefaultVersionName=>T("DefaultVersionName"); private static string T(string key) { return StringResourceSystemFacade.GetString("Composite.Management", key); @@ -2675,6 +2679,14 @@ public static class Composite_Plugins_GeneratedDataTypesElementProvider { public static string PublishDate_Label=>T("PublishDate.Label"); ///"Specify at which date and time you want the data to be published automatically." public static string PublishDate_Help=>T("PublishDate.Help"); +///"Date Created" +public static string DateCreated_Label=>T("DateCreated.Label"); +///"Date Modified" +public static string DateModified_Label=>T("DateModified.Label"); +///"Author" +public static string CreatedBy_Label=>T("CreatedBy.Label"); +///"Author" +public static string ChangedBy_Label=>T("ChangedBy.Label"); ///"Unpublish date" public static string UnpublishDate_Label=>T("UnpublishDate.Label"); ///"Specify at which date and time you want the data to be unpublished automatically." @@ -3525,14 +3537,6 @@ public static class Composite_Plugins_PageElementProvider { public static string EditPage_LabelAbstract=>T("EditPage.LabelAbstract"); ///"Use this field for a short description of the page" public static string EditPage_LabelAbstractHelp=>T("EditPage.LabelAbstractHelp"); -///"Publish date" -public static string EditPage_LabelPublishDate=>T("EditPage.LabelPublishDate"); -///"Specify at which date and time you want the page to be published automatically." -public static string EditPage_HelpPublishDate=>T("EditPage.HelpPublishDate"); -///"Unpublish date" -public static string EditPage_LabelUnpublishDate=>T("EditPage.LabelUnpublishDate"); -///"Specify at which date and time you want the page to be unpublished automatically." -public static string EditPage_HelpUnpublishDate=>T("EditPage.HelpUnpublishDate"); ///"Content" public static string EditPage_LabelContent=>T("EditPage.LabelContent"); ///"Preview" @@ -3663,6 +3667,14 @@ public static class Composite_Plugins_PageElementProvider { public static string DeletePageWorkflow_HasCompositionsTitle=>T("DeletePageWorkflow.HasCompositionsTitle"); ///"This page has one or more page folders or metadata fields defined on it. Delete these first." public static string DeletePageWorkflow_HasCompositionsMessage=>T("DeletePageWorkflow.HasCompositionsMessage"); +///"Delete page versions" +public static string DeletePageWorkflow_ConfirmAllVersionsDeletion_DialogLabel=>T("DeletePageWorkflow.ConfirmAllVersionsDeletion.DialogLabel"); +///"This page contains multiple versions" +public static string DeletePageWorkflow_ConfirmAllVersionsDeletion_Text=>T("DeletePageWorkflow.ConfirmAllVersionsDeletion.Text"); +///"Delete all versions" +public static string DeletePageWorkflow_ConfirmAllVersionsDeletion_DeleteAllVersions=>T("DeletePageWorkflow.ConfirmAllVersionsDeletion.DeleteAllVersions"); +///"Delete only current version" +public static string DeletePageWorkflow_ConfirmAllVersionsDeletion_DeleteCurrentVersion=>T("DeletePageWorkflow.ConfirmAllVersionsDeletion.DeleteCurrentVersion"); ///"Page Title" public static string ViewUnpublishedItems_PageTitleLabel=>T("ViewUnpublishedItems.PageTitleLabel"); ///"Version" @@ -3671,11 +3683,11 @@ public static class Composite_Plugins_PageElementProvider { public static string ViewUnpublishedItems_StatusLabel=>T("ViewUnpublishedItems.StatusLabel"); ///"Publish Date" public static string ViewUnpublishedItems_PublishDateLabel=>T("ViewUnpublishedItems.PublishDateLabel"); -///"This is the date and time that has been set for the page to be published automatically. To update or remove, see the Publication Schedule in Edit Page mode. Otherwise you can override these dates by publishing manually from this view." +///"Date and time the page has been scheduled to publish automatically. To edit, see the Publication Schedule in Edit Page mode." public static string ViewUnpublishedItems_PublishDateHelp=>T("ViewUnpublishedItems.PublishDateHelp"); ///"Unpublish Date" public static string ViewUnpublishedItems_UnpublishDateLabel=>T("ViewUnpublishedItems.UnpublishDateLabel"); -///"This is the date and time that has been set for the page to be unpublished automatically. To update or remove, see the Publication Schedule in Edit Page mode." +///"Date and time the page has been scheduled to unpublish automatically. To edit, see the Publication Schedule in Edit Page mode." public static string ViewUnpublishedItems_UnpublishDateHelp=>T("ViewUnpublishedItems.UnpublishDateHelp"); ///"Date Created" public static string ViewUnpublishedItems_DateCreatedLabel=>T("ViewUnpublishedItems.DateCreatedLabel"); @@ -5204,266 +5216,266 @@ private static string T(string key) /// [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] - public static class Composite_Plugins_TimezoneAbbriviations { + public static class Composite_Plugins_TimezoneAbbreviations { ///"Etc/GMT+12" -public static string TimezoneAbbriviations_Dateline_Standard_Time=>T("TimezoneAbbriviations.Dateline Standard Time"); +public static string TimezoneAbbreviations_Dateline_Standard_Time=>T("TimezoneAbbreviations.Dateline Standard Time"); ///"Etc/GMT+11" -public static string TimezoneAbbriviations_UTC_11=>T("TimezoneAbbriviations.UTC-11"); +public static string TimezoneAbbreviations_UTC_11=>T("TimezoneAbbreviations.UTC-11"); ///"UTC-10" -public static string TimezoneAbbriviations_Aleutian_Standard_Time=>T("TimezoneAbbriviations.Aleutian Standard Time"); +public static string TimezoneAbbreviations_Aleutian_Standard_Time=>T("TimezoneAbbreviations.Aleutian Standard Time"); ///"HST" -public static string TimezoneAbbriviations_Hawaiian_Standard_Time=>T("TimezoneAbbriviations.Hawaiian Standard Time"); +public static string TimezoneAbbreviations_Hawaiian_Standard_Time=>T("TimezoneAbbreviations.Hawaiian Standard Time"); ///"MART" -public static string TimezoneAbbriviations_Marquesas_Standard_Time=>T("TimezoneAbbriviations.Marquesas Standard Time"); +public static string TimezoneAbbreviations_Marquesas_Standard_Time=>T("TimezoneAbbreviations.Marquesas Standard Time"); ///"AKST" -public static string TimezoneAbbriviations_Alaskan_Standard_Time=>T("TimezoneAbbriviations.Alaskan Standard Time"); +public static string TimezoneAbbreviations_Alaskan_Standard_Time=>T("TimezoneAbbreviations.Alaskan Standard Time"); ///"UTC-09" -public static string TimezoneAbbriviations_UTC_09=>T("TimezoneAbbriviations.UTC-09"); +public static string TimezoneAbbreviations_UTC_09=>T("TimezoneAbbreviations.UTC-09"); ///"PST" -public static string TimezoneAbbriviations_Pacific_Standard_Time_Mexico=>T("TimezoneAbbriviations.Pacific Standard Time (Mexico)"); +public static string TimezoneAbbreviations_Pacific_Standard_Time_Mexico=>T("TimezoneAbbreviations.Pacific Standard Time (Mexico)"); ///"UTC-08" -public static string TimezoneAbbriviations_UTC_08=>T("TimezoneAbbriviations.UTC-08"); +public static string TimezoneAbbreviations_UTC_08=>T("TimezoneAbbreviations.UTC-08"); ///"PST" -public static string TimezoneAbbriviations_Pacific_Standard_Time=>T("TimezoneAbbriviations.Pacific Standard Time"); +public static string TimezoneAbbreviations_Pacific_Standard_Time=>T("TimezoneAbbreviations.Pacific Standard Time"); ///"MST" -public static string TimezoneAbbriviations_US_Mountain_Standard_Time=>T("TimezoneAbbriviations.US Mountain Standard Time"); +public static string TimezoneAbbreviations_US_Mountain_Standard_Time=>T("TimezoneAbbreviations.US Mountain Standard Time"); ///"MST" -public static string TimezoneAbbriviations_Mountain_Standard_Time_Mexico=>T("TimezoneAbbriviations.Mountain Standard Time (Mexico)"); +public static string TimezoneAbbreviations_Mountain_Standard_Time_Mexico=>T("TimezoneAbbreviations.Mountain Standard Time (Mexico)"); ///"MST" -public static string TimezoneAbbriviations_Mountain_Standard_Time=>T("TimezoneAbbriviations.Mountain Standard Time"); +public static string TimezoneAbbreviations_Mountain_Standard_Time=>T("TimezoneAbbreviations.Mountain Standard Time"); ///"CST" -public static string TimezoneAbbriviations_Central_America_Standard_Time=>T("TimezoneAbbriviations.Central America Standard Time"); +public static string TimezoneAbbreviations_Central_America_Standard_Time=>T("TimezoneAbbreviations.Central America Standard Time"); ///"CST" -public static string TimezoneAbbriviations_Central_Standard_Time=>T("TimezoneAbbriviations.Central Standard Time"); +public static string TimezoneAbbreviations_Central_Standard_Time=>T("TimezoneAbbreviations.Central Standard Time"); ///"EASST" -public static string TimezoneAbbriviations_Easter_Island_Standard_Time=>T("TimezoneAbbriviations.Easter Island Standard Time"); +public static string TimezoneAbbreviations_Easter_Island_Standard_Time=>T("TimezoneAbbreviations.Easter Island Standard Time"); ///"CST" -public static string TimezoneAbbriviations_Central_Standard_Time_Mexico=>T("TimezoneAbbriviations.Central Standard Time (Mexico)"); +public static string TimezoneAbbreviations_Central_Standard_Time_Mexico=>T("TimezoneAbbreviations.Central Standard Time (Mexico)"); ///"CST" -public static string TimezoneAbbriviations_Canada_Central_Standard_Time=>T("TimezoneAbbriviations.Canada Central Standard Time"); +public static string TimezoneAbbreviations_Canada_Central_Standard_Time=>T("TimezoneAbbreviations.Canada Central Standard Time"); ///"SAPST" -public static string TimezoneAbbriviations_SA_Pacific_Standard_Time=>T("TimezoneAbbriviations.SA Pacific Standard Time"); +public static string TimezoneAbbreviations_SA_Pacific_Standard_Time=>T("TimezoneAbbreviations.SA Pacific Standard Time"); ///"EST" -public static string TimezoneAbbriviations_Eastern_Standard_Time_Mexico=>T("TimezoneAbbriviations.Eastern Standard Time (Mexico)"); +public static string TimezoneAbbreviations_Eastern_Standard_Time_Mexico=>T("TimezoneAbbreviations.Eastern Standard Time (Mexico)"); ///"EST" -public static string TimezoneAbbriviations_Eastern_Standard_Time=>T("TimezoneAbbriviations.Eastern Standard Time"); +public static string TimezoneAbbreviations_Eastern_Standard_Time=>T("TimezoneAbbreviations.Eastern Standard Time"); ///"EST" -public static string TimezoneAbbriviations_Haiti_Standard_Time=>T("TimezoneAbbriviations.Haiti Standard Time"); +public static string TimezoneAbbreviations_Haiti_Standard_Time=>T("TimezoneAbbreviations.Haiti Standard Time"); ///"UTC-05" -public static string TimezoneAbbriviations_Cuba_Standard_Time=>T("TimezoneAbbriviations.Cuba Standard Time"); +public static string TimezoneAbbreviations_Cuba_Standard_Time=>T("TimezoneAbbreviations.Cuba Standard Time"); ///"EST" -public static string TimezoneAbbriviations_US_Eastern_Standard_Time=>T("TimezoneAbbriviations.US Eastern Standard Time"); +public static string TimezoneAbbreviations_US_Eastern_Standard_Time=>T("TimezoneAbbreviations.US Eastern Standard Time"); ///"VET" -public static string TimezoneAbbriviations_Venezuela_Standard_Time=>T("TimezoneAbbriviations.Venezuela Standard Time"); +public static string TimezoneAbbreviations_Venezuela_Standard_Time=>T("TimezoneAbbreviations.Venezuela Standard Time"); ///"PYST" -public static string TimezoneAbbriviations_Paraguay_Standard_Time=>T("TimezoneAbbriviations.Paraguay Standard Time"); +public static string TimezoneAbbreviations_Paraguay_Standard_Time=>T("TimezoneAbbreviations.Paraguay Standard Time"); ///"AST" -public static string TimezoneAbbriviations_Atlantic_Standard_Time=>T("TimezoneAbbriviations.Atlantic Standard Time"); +public static string TimezoneAbbreviations_Atlantic_Standard_Time=>T("TimezoneAbbreviations.Atlantic Standard Time"); ///"AMST" -public static string TimezoneAbbriviations_Central_Brazilian_Standard_Time=>T("TimezoneAbbriviations.Central Brazilian Standard Time"); +public static string TimezoneAbbreviations_Central_Brazilian_Standard_Time=>T("TimezoneAbbreviations.Central Brazilian Standard Time"); ///"SAWST" -public static string TimezoneAbbriviations_SA_Western_Standard_Time=>T("TimezoneAbbriviations.SA Western Standard Time"); +public static string TimezoneAbbreviations_SA_Western_Standard_Time=>T("TimezoneAbbreviations.SA Western Standard Time"); ///"CLST" -public static string TimezoneAbbriviations_Pacific_SA_Standard_Time=>T("TimezoneAbbriviations.Pacific SA Standard Time"); +public static string TimezoneAbbreviations_Pacific_SA_Standard_Time=>T("TimezoneAbbreviations.Pacific SA Standard Time"); ///"UTC-04" -public static string TimezoneAbbriviations_Turks_And_Caicos_Standard_Time=>T("TimezoneAbbriviations.Turks And Caicos Standard Time"); +public static string TimezoneAbbreviations_Turks_And_Caicos_Standard_Time=>T("TimezoneAbbreviations.Turks And Caicos Standard Time"); ///"NST" -public static string TimezoneAbbriviations_Newfoundland_Standard_Time=>T("TimezoneAbbriviations.Newfoundland Standard Time"); +public static string TimezoneAbbreviations_Newfoundland_Standard_Time=>T("TimezoneAbbreviations.Newfoundland Standard Time"); ///"UTC-03" -public static string TimezoneAbbriviations_Tocantins_Standard_Time=>T("TimezoneAbbriviations.Tocantins Standard Time"); +public static string TimezoneAbbreviations_Tocantins_Standard_Time=>T("TimezoneAbbreviations.Tocantins Standard Time"); ///"BRST" -public static string TimezoneAbbriviations_E__South_America_Standard_Time=>T("TimezoneAbbriviations.E. South America Standard Time"); +public static string TimezoneAbbreviations_E__South_America_Standard_Time=>T("TimezoneAbbreviations.E. South America Standard Time"); ///"GFT" -public static string TimezoneAbbriviations_SA_Eastern_Standard_Time=>T("TimezoneAbbriviations.SA Eastern Standard Time"); +public static string TimezoneAbbreviations_SA_Eastern_Standard_Time=>T("TimezoneAbbreviations.SA Eastern Standard Time"); ///"ART" -public static string TimezoneAbbriviations_Argentina_Standard_Time=>T("TimezoneAbbriviations.Argentina Standard Time"); +public static string TimezoneAbbreviations_Argentina_Standard_Time=>T("TimezoneAbbreviations.Argentina Standard Time"); ///"WGT" -public static string TimezoneAbbriviations_Greenland_Standard_Time=>T("TimezoneAbbriviations.Greenland Standard Time"); +public static string TimezoneAbbreviations_Greenland_Standard_Time=>T("TimezoneAbbreviations.Greenland Standard Time"); ///"UYT" -public static string TimezoneAbbriviations_Montevideo_Standard_Time=>T("TimezoneAbbriviations.Montevideo Standard Time"); +public static string TimezoneAbbreviations_Montevideo_Standard_Time=>T("TimezoneAbbreviations.Montevideo Standard Time"); ///"UTC-03" -public static string TimezoneAbbriviations_Saint_Pierre_Standard_Time=>T("TimezoneAbbriviations.Saint Pierre Standard Time"); +public static string TimezoneAbbreviations_Saint_Pierre_Standard_Time=>T("TimezoneAbbreviations.Saint Pierre Standard Time"); ///"BRT" -public static string TimezoneAbbriviations_Bahia_Standard_Time=>T("TimezoneAbbriviations.Bahia Standard Time"); +public static string TimezoneAbbreviations_Bahia_Standard_Time=>T("TimezoneAbbreviations.Bahia Standard Time"); ///"Etc/GMT+2" -public static string TimezoneAbbriviations_UTC_02=>T("TimezoneAbbriviations.UTC-02"); +public static string TimezoneAbbreviations_UTC_02=>T("TimezoneAbbreviations.UTC-02"); ///"AST" -public static string TimezoneAbbriviations_Mid_Atlantic_Standard_Time=>T("TimezoneAbbriviations.Mid-Atlantic Standard Time"); +public static string TimezoneAbbreviations_Mid_Atlantic_Standard_Time=>T("TimezoneAbbreviations.Mid-Atlantic Standard Time"); ///"AZOT" -public static string TimezoneAbbriviations_Azores_Standard_Time=>T("TimezoneAbbriviations.Azores Standard Time"); +public static string TimezoneAbbreviations_Azores_Standard_Time=>T("TimezoneAbbreviations.Azores Standard Time"); ///"CVT" -public static string TimezoneAbbriviations_Cape_Verde_Standard_Time=>T("TimezoneAbbriviations.Cape Verde Standard Time"); +public static string TimezoneAbbreviations_Cape_Verde_Standard_Time=>T("TimezoneAbbreviations.Cape Verde Standard Time"); ///"WET" -public static string TimezoneAbbriviations_Morocco_Standard_Time=>T("TimezoneAbbriviations.Morocco Standard Time"); +public static string TimezoneAbbreviations_Morocco_Standard_Time=>T("TimezoneAbbreviations.Morocco Standard Time"); ///"Etc/GMT" -public static string TimezoneAbbriviations_UTC=>T("TimezoneAbbriviations.UTC"); +public static string TimezoneAbbreviations_UTC=>T("TimezoneAbbreviations.UTC"); ///"GMT" -public static string TimezoneAbbriviations_GMT_Standard_Time=>T("TimezoneAbbriviations.GMT Standard Time"); +public static string TimezoneAbbreviations_GMT_Standard_Time=>T("TimezoneAbbreviations.GMT Standard Time"); ///"GMT" -public static string TimezoneAbbriviations_Greenwich_Standard_Time=>T("TimezoneAbbriviations.Greenwich Standard Time"); +public static string TimezoneAbbreviations_Greenwich_Standard_Time=>T("TimezoneAbbreviations.Greenwich Standard Time"); ///"CET" -public static string TimezoneAbbriviations_W__Europe_Standard_Time=>T("TimezoneAbbriviations.W. Europe Standard Time"); +public static string TimezoneAbbreviations_W__Europe_Standard_Time=>T("TimezoneAbbreviations.W. Europe Standard Time"); ///"CET" -public static string TimezoneAbbriviations_Central_Europe_Standard_Time=>T("TimezoneAbbriviations.Central Europe Standard Time"); +public static string TimezoneAbbreviations_Central_Europe_Standard_Time=>T("TimezoneAbbreviations.Central Europe Standard Time"); ///"CET" -public static string TimezoneAbbriviations_Romance_Standard_Time=>T("TimezoneAbbriviations.Romance Standard Time"); +public static string TimezoneAbbreviations_Romance_Standard_Time=>T("TimezoneAbbreviations.Romance Standard Time"); ///"CET" -public static string TimezoneAbbriviations_Central_European_Standard_Time=>T("TimezoneAbbriviations.Central European Standard Time"); +public static string TimezoneAbbreviations_Central_European_Standard_Time=>T("TimezoneAbbreviations.Central European Standard Time"); ///"WAT" -public static string TimezoneAbbriviations_W__Central_Africa_Standard_Time=>T("TimezoneAbbriviations.W. Central Africa Standard Time"); +public static string TimezoneAbbreviations_W__Central_Africa_Standard_Time=>T("TimezoneAbbreviations.W. Central Africa Standard Time"); ///"WAST" -public static string TimezoneAbbriviations_Namibia_Standard_Time=>T("TimezoneAbbriviations.Namibia Standard Time"); +public static string TimezoneAbbreviations_Namibia_Standard_Time=>T("TimezoneAbbreviations.Namibia Standard Time"); ///"EET" -public static string TimezoneAbbriviations_Jordan_Standard_Time=>T("TimezoneAbbriviations.Jordan Standard Time"); +public static string TimezoneAbbreviations_Jordan_Standard_Time=>T("TimezoneAbbreviations.Jordan Standard Time"); ///"EET" -public static string TimezoneAbbriviations_GTB_Standard_Time=>T("TimezoneAbbriviations.GTB Standard Time"); +public static string TimezoneAbbreviations_GTB_Standard_Time=>T("TimezoneAbbreviations.GTB Standard Time"); ///"EET" -public static string TimezoneAbbriviations_Middle_East_Standard_Time=>T("TimezoneAbbriviations.Middle East Standard Time"); +public static string TimezoneAbbreviations_Middle_East_Standard_Time=>T("TimezoneAbbreviations.Middle East Standard Time"); ///"EET" -public static string TimezoneAbbriviations_Egypt_Standard_Time=>T("TimezoneAbbriviations.Egypt Standard Time"); +public static string TimezoneAbbreviations_Egypt_Standard_Time=>T("TimezoneAbbreviations.Egypt Standard Time"); ///"EET" -public static string TimezoneAbbriviations_Syria_Standard_Time=>T("TimezoneAbbriviations.Syria Standard Time"); +public static string TimezoneAbbreviations_Syria_Standard_Time=>T("TimezoneAbbreviations.Syria Standard Time"); ///"EET" -public static string TimezoneAbbriviations_E__Europe_Standard_Time=>T("TimezoneAbbriviations.E. Europe Standard Time"); +public static string TimezoneAbbreviations_E__Europe_Standard_Time=>T("TimezoneAbbreviations.E. Europe Standard Time"); ///"UTC+02" -public static string TimezoneAbbriviations_West_Bank_Standard_Time=>T("TimezoneAbbriviations.West Bank Standard Time"); +public static string TimezoneAbbreviations_West_Bank_Standard_Time=>T("TimezoneAbbreviations.West Bank Standard Time"); ///"SAST" -public static string TimezoneAbbriviations_South_Africa_Standard_Time=>T("TimezoneAbbriviations.South Africa Standard Time"); +public static string TimezoneAbbreviations_South_Africa_Standard_Time=>T("TimezoneAbbreviations.South Africa Standard Time"); ///"EET" -public static string TimezoneAbbriviations_FLE_Standard_Time=>T("TimezoneAbbriviations.FLE Standard Time"); +public static string TimezoneAbbreviations_FLE_Standard_Time=>T("TimezoneAbbreviations.FLE Standard Time"); ///"EET" -public static string TimezoneAbbriviations_Turkey_Standard_Time=>T("TimezoneAbbriviations.Turkey Standard Time"); +public static string TimezoneAbbreviations_Turkey_Standard_Time=>T("TimezoneAbbreviations.Turkey Standard Time"); ///"IST" -public static string TimezoneAbbriviations_Israel_Standard_Time=>T("TimezoneAbbriviations.Israel Standard Time"); +public static string TimezoneAbbreviations_Israel_Standard_Time=>T("TimezoneAbbreviations.Israel Standard Time"); ///"EET" -public static string TimezoneAbbriviations_Kaliningrad_Standard_Time=>T("TimezoneAbbriviations.Kaliningrad Standard Time"); +public static string TimezoneAbbreviations_Kaliningrad_Standard_Time=>T("TimezoneAbbreviations.Kaliningrad Standard Time"); ///"EET" -public static string TimezoneAbbriviations_Libya_Standard_Time=>T("TimezoneAbbriviations.Libya Standard Time"); +public static string TimezoneAbbreviations_Libya_Standard_Time=>T("TimezoneAbbreviations.Libya Standard Time"); ///"AST" -public static string TimezoneAbbriviations_Arabic_Standard_Time=>T("TimezoneAbbriviations.Arabic Standard Time"); +public static string TimezoneAbbreviations_Arabic_Standard_Time=>T("TimezoneAbbreviations.Arabic Standard Time"); ///"AST" -public static string TimezoneAbbriviations_Arab_Standard_Time=>T("TimezoneAbbriviations.Arab Standard Time"); +public static string TimezoneAbbreviations_Arab_Standard_Time=>T("TimezoneAbbreviations.Arab Standard Time"); ///"MSK" -public static string TimezoneAbbriviations_Belarus_Standard_Time=>T("TimezoneAbbriviations.Belarus Standard Time"); +public static string TimezoneAbbreviations_Belarus_Standard_Time=>T("TimezoneAbbreviations.Belarus Standard Time"); ///"MSK" -public static string TimezoneAbbriviations_Russian_Standard_Time=>T("TimezoneAbbriviations.Russian Standard Time"); +public static string TimezoneAbbreviations_Russian_Standard_Time=>T("TimezoneAbbreviations.Russian Standard Time"); ///"EAT" -public static string TimezoneAbbriviations_E__Africa_Standard_Time=>T("TimezoneAbbriviations.E. Africa Standard Time"); +public static string TimezoneAbbreviations_E__Africa_Standard_Time=>T("TimezoneAbbreviations.E. Africa Standard Time"); ///"MSK" -public static string TimezoneAbbriviations_Astrakhan_Standard_Time=>T("TimezoneAbbriviations.Astrakhan Standard Time"); +public static string TimezoneAbbreviations_Astrakhan_Standard_Time=>T("TimezoneAbbreviations.Astrakhan Standard Time"); ///"IRST" -public static string TimezoneAbbriviations_Iran_Standard_Time=>T("TimezoneAbbriviations.Iran Standard Time"); +public static string TimezoneAbbreviations_Iran_Standard_Time=>T("TimezoneAbbreviations.Iran Standard Time"); ///"GST" -public static string TimezoneAbbriviations_Arabian_Standard_Time=>T("TimezoneAbbriviations.Arabian Standard Time"); +public static string TimezoneAbbreviations_Arabian_Standard_Time=>T("TimezoneAbbreviations.Arabian Standard Time"); ///"AZT" -public static string TimezoneAbbriviations_Azerbaijan_Standard_Time=>T("TimezoneAbbriviations.Azerbaijan Standard Time"); +public static string TimezoneAbbreviations_Azerbaijan_Standard_Time=>T("TimezoneAbbreviations.Azerbaijan Standard Time"); ///"SAMT" -public static string TimezoneAbbriviations_Russia_Time_Zone_3=>T("TimezoneAbbriviations.Russia Time Zone 3"); +public static string TimezoneAbbreviations_Russia_Time_Zone_3=>T("TimezoneAbbreviations.Russia Time Zone 3"); ///"MUT" -public static string TimezoneAbbriviations_Mauritius_Standard_Time=>T("TimezoneAbbriviations.Mauritius Standard Time"); +public static string TimezoneAbbreviations_Mauritius_Standard_Time=>T("TimezoneAbbreviations.Mauritius Standard Time"); ///"GET" -public static string TimezoneAbbriviations_Georgian_Standard_Time=>T("TimezoneAbbriviations.Georgian Standard Time"); +public static string TimezoneAbbreviations_Georgian_Standard_Time=>T("TimezoneAbbreviations.Georgian Standard Time"); ///"AMT" -public static string TimezoneAbbriviations_Caucasus_Standard_Time=>T("TimezoneAbbriviations.Caucasus Standard Time"); +public static string TimezoneAbbreviations_Caucasus_Standard_Time=>T("TimezoneAbbreviations.Caucasus Standard Time"); ///"AFT" -public static string TimezoneAbbriviations_Afghanistan_Standard_Time=>T("TimezoneAbbriviations.Afghanistan Standard Time"); +public static string TimezoneAbbreviations_Afghanistan_Standard_Time=>T("TimezoneAbbreviations.Afghanistan Standard Time"); ///"UZT" -public static string TimezoneAbbriviations_West_Asia_Standard_Time=>T("TimezoneAbbriviations.West Asia Standard Time"); +public static string TimezoneAbbreviations_West_Asia_Standard_Time=>T("TimezoneAbbreviations.West Asia Standard Time"); ///"YEKT" -public static string TimezoneAbbriviations_Ekaterinburg_Standard_Time=>T("TimezoneAbbriviations.Ekaterinburg Standard Time"); +public static string TimezoneAbbreviations_Ekaterinburg_Standard_Time=>T("TimezoneAbbreviations.Ekaterinburg Standard Time"); ///"PKT" -public static string TimezoneAbbriviations_Pakistan_Standard_Time=>T("TimezoneAbbriviations.Pakistan Standard Time"); +public static string TimezoneAbbreviations_Pakistan_Standard_Time=>T("TimezoneAbbreviations.Pakistan Standard Time"); ///"IST" -public static string TimezoneAbbriviations_India_Standard_Time=>T("TimezoneAbbriviations.India Standard Time"); +public static string TimezoneAbbreviations_India_Standard_Time=>T("TimezoneAbbreviations.India Standard Time"); ///"IST" -public static string TimezoneAbbriviations_Sri_Lanka_Standard_Time=>T("TimezoneAbbriviations.Sri Lanka Standard Time"); +public static string TimezoneAbbreviations_Sri_Lanka_Standard_Time=>T("TimezoneAbbreviations.Sri Lanka Standard Time"); ///"NPT" -public static string TimezoneAbbriviations_Nepal_Standard_Time=>T("TimezoneAbbriviations.Nepal Standard Time"); +public static string TimezoneAbbreviations_Nepal_Standard_Time=>T("TimezoneAbbreviations.Nepal Standard Time"); ///"ALMT" -public static string TimezoneAbbriviations_Central_Asia_Standard_Time=>T("TimezoneAbbriviations.Central Asia Standard Time"); +public static string TimezoneAbbreviations_Central_Asia_Standard_Time=>T("TimezoneAbbreviations.Central Asia Standard Time"); ///"BDT" -public static string TimezoneAbbriviations_Bangladesh_Standard_Time=>T("TimezoneAbbriviations.Bangladesh Standard Time"); +public static string TimezoneAbbreviations_Bangladesh_Standard_Time=>T("TimezoneAbbreviations.Bangladesh Standard Time"); ///"NOVT" -public static string TimezoneAbbriviations_N__Central_Asia_Standard_Time=>T("TimezoneAbbriviations.N. Central Asia Standard Time"); +public static string TimezoneAbbreviations_N__Central_Asia_Standard_Time=>T("TimezoneAbbreviations.N. Central Asia Standard Time"); ///"MSK+3" -public static string TimezoneAbbriviations_Altai_Standard_Time=>T("TimezoneAbbriviations.Altai Standard Time"); +public static string TimezoneAbbreviations_Altai_Standard_Time=>T("TimezoneAbbreviations.Altai Standard Time"); ///"MMT" -public static string TimezoneAbbriviations_Myanmar_Standard_Time=>T("TimezoneAbbriviations.Myanmar Standard Time"); +public static string TimezoneAbbreviations_Myanmar_Standard_Time=>T("TimezoneAbbreviations.Myanmar Standard Time"); ///"ICT" -public static string TimezoneAbbriviations_SE_Asia_Standard_Time=>T("TimezoneAbbriviations.SE Asia Standard Time"); +public static string TimezoneAbbreviations_SE_Asia_Standard_Time=>T("TimezoneAbbreviations.SE Asia Standard Time"); ///"UTC+07" -public static string TimezoneAbbriviations_W__Mongolia_Standard_Time=>T("TimezoneAbbriviations.W. Mongolia Standard Time"); +public static string TimezoneAbbreviations_W__Mongolia_Standard_Time=>T("TimezoneAbbreviations.W. Mongolia Standard Time"); ///"KRAT" -public static string TimezoneAbbriviations_North_Asia_Standard_Time=>T("TimezoneAbbriviations.North Asia Standard Time"); +public static string TimezoneAbbreviations_North_Asia_Standard_Time=>T("TimezoneAbbreviations.North Asia Standard Time"); ///"UTC+07" -public static string TimezoneAbbriviations_Tomsk_Standard_Time=>T("TimezoneAbbriviations.Tomsk Standard Time"); +public static string TimezoneAbbreviations_Tomsk_Standard_Time=>T("TimezoneAbbreviations.Tomsk Standard Time"); ///"CST" -public static string TimezoneAbbriviations_China_Standard_Time=>T("TimezoneAbbriviations.China Standard Time"); +public static string TimezoneAbbreviations_China_Standard_Time=>T("TimezoneAbbreviations.China Standard Time"); ///"IRKT" -public static string TimezoneAbbriviations_North_Asia_East_Standard_Time=>T("TimezoneAbbriviations.North Asia East Standard Time"); +public static string TimezoneAbbreviations_North_Asia_East_Standard_Time=>T("TimezoneAbbreviations.North Asia East Standard Time"); ///"SGT" -public static string TimezoneAbbriviations_Singapore_Standard_Time=>T("TimezoneAbbriviations.Singapore Standard Time"); +public static string TimezoneAbbreviations_Singapore_Standard_Time=>T("TimezoneAbbreviations.Singapore Standard Time"); ///"AWST" -public static string TimezoneAbbriviations_W__Australia_Standard_Time=>T("TimezoneAbbriviations.W. Australia Standard Time"); +public static string TimezoneAbbreviations_W__Australia_Standard_Time=>T("TimezoneAbbreviations.W. Australia Standard Time"); ///"CST" -public static string TimezoneAbbriviations_Taipei_Standard_Time=>T("TimezoneAbbriviations.Taipei Standard Time"); +public static string TimezoneAbbreviations_Taipei_Standard_Time=>T("TimezoneAbbreviations.Taipei Standard Time"); ///"ULAT" -public static string TimezoneAbbriviations_Ulaanbaatar_Standard_Time=>T("TimezoneAbbriviations.Ulaanbaatar Standard Time"); +public static string TimezoneAbbreviations_Ulaanbaatar_Standard_Time=>T("TimezoneAbbreviations.Ulaanbaatar Standard Time"); ///"KST" -public static string TimezoneAbbriviations_North_Korea_Standard_Time=>T("TimezoneAbbriviations.North Korea Standard Time"); +public static string TimezoneAbbreviations_North_Korea_Standard_Time=>T("TimezoneAbbreviations.North Korea Standard Time"); ///"UTC+09" -public static string TimezoneAbbriviations_Transbaikal_Standard_Time=>T("TimezoneAbbriviations.Transbaikal Standard Time"); +public static string TimezoneAbbreviations_Transbaikal_Standard_Time=>T("TimezoneAbbreviations.Transbaikal Standard Time"); ///"JST" -public static string TimezoneAbbriviations_Tokyo_Standard_Time=>T("TimezoneAbbriviations.Tokyo Standard Time"); +public static string TimezoneAbbreviations_Tokyo_Standard_Time=>T("TimezoneAbbreviations.Tokyo Standard Time"); ///"KST" -public static string TimezoneAbbriviations_Korea_Standard_Time=>T("TimezoneAbbriviations.Korea Standard Time"); +public static string TimezoneAbbreviations_Korea_Standard_Time=>T("TimezoneAbbreviations.Korea Standard Time"); ///"YAKT" -public static string TimezoneAbbriviations_Yakutsk_Standard_Time=>T("TimezoneAbbriviations.Yakutsk Standard Time"); +public static string TimezoneAbbreviations_Yakutsk_Standard_Time=>T("TimezoneAbbreviations.Yakutsk Standard Time"); ///"ACDT" -public static string TimezoneAbbriviations_Cen__Australia_Standard_Time=>T("TimezoneAbbriviations.Cen. Australia Standard Time"); +public static string TimezoneAbbreviations_Cen__Australia_Standard_Time=>T("TimezoneAbbreviations.Cen. Australia Standard Time"); ///"ACST" -public static string TimezoneAbbriviations_AUS_Central_Standard_Time=>T("TimezoneAbbriviations.AUS Central Standard Time"); +public static string TimezoneAbbreviations_AUS_Central_Standard_Time=>T("TimezoneAbbreviations.AUS Central Standard Time"); ///"AEST" -public static string TimezoneAbbriviations_E__Australia_Standard_Time=>T("TimezoneAbbriviations.E. Australia Standard Time"); +public static string TimezoneAbbreviations_E__Australia_Standard_Time=>T("TimezoneAbbreviations.E. Australia Standard Time"); ///"AEDT" -public static string TimezoneAbbriviations_AUS_Eastern_Standard_Time=>T("TimezoneAbbriviations.AUS Eastern Standard Time"); +public static string TimezoneAbbreviations_AUS_Eastern_Standard_Time=>T("TimezoneAbbreviations.AUS Eastern Standard Time"); ///"PGT" -public static string TimezoneAbbriviations_West_Pacific_Standard_Time=>T("TimezoneAbbriviations.West Pacific Standard Time"); +public static string TimezoneAbbreviations_West_Pacific_Standard_Time=>T("TimezoneAbbreviations.West Pacific Standard Time"); ///"AEDT" -public static string TimezoneAbbriviations_Tasmania_Standard_Time=>T("TimezoneAbbriviations.Tasmania Standard Time"); +public static string TimezoneAbbreviations_Tasmania_Standard_Time=>T("TimezoneAbbreviations.Tasmania Standard Time"); ///"MAGT" -public static string TimezoneAbbriviations_Magadan_Standard_Time=>T("TimezoneAbbriviations.Magadan Standard Time"); +public static string TimezoneAbbreviations_Magadan_Standard_Time=>T("TimezoneAbbreviations.Magadan Standard Time"); ///"VLAT" -public static string TimezoneAbbriviations_Vladivostok_Standard_Time=>T("TimezoneAbbriviations.Vladivostok Standard Time"); +public static string TimezoneAbbreviations_Vladivostok_Standard_Time=>T("TimezoneAbbreviations.Vladivostok Standard Time"); ///"SRET" -public static string TimezoneAbbriviations_Russia_Time_Zone_10=>T("TimezoneAbbriviations.Russia Time Zone 10"); +public static string TimezoneAbbreviations_Russia_Time_Zone_10=>T("TimezoneAbbreviations.Russia Time Zone 10"); ///"UTC+11" -public static string TimezoneAbbriviations_Norfolk_Standard_Time=>T("TimezoneAbbriviations.Norfolk Standard Time"); +public static string TimezoneAbbreviations_Norfolk_Standard_Time=>T("TimezoneAbbreviations.Norfolk Standard Time"); ///"UTC+11" -public static string TimezoneAbbriviations_Sakhalin_Standard_Time=>T("TimezoneAbbriviations.Sakhalin Standard Time"); +public static string TimezoneAbbreviations_Sakhalin_Standard_Time=>T("TimezoneAbbreviations.Sakhalin Standard Time"); ///"SBT" -public static string TimezoneAbbriviations_Central_Pacific_Standard_Time=>T("TimezoneAbbriviations.Central Pacific Standard Time"); +public static string TimezoneAbbreviations_Central_Pacific_Standard_Time=>T("TimezoneAbbreviations.Central Pacific Standard Time"); ///"PETT" -public static string TimezoneAbbriviations_Russia_Time_Zone_11=>T("TimezoneAbbriviations.Russia Time Zone 11"); +public static string TimezoneAbbreviations_Russia_Time_Zone_11=>T("TimezoneAbbreviations.Russia Time Zone 11"); ///"NZDT" -public static string TimezoneAbbriviations_New_Zealand_Standard_Time=>T("TimezoneAbbriviations.New Zealand Standard Time"); +public static string TimezoneAbbreviations_New_Zealand_Standard_Time=>T("TimezoneAbbreviations.New Zealand Standard Time"); ///"Etc/GMT-12" -public static string TimezoneAbbriviations_UTC12=>T("TimezoneAbbriviations.UTC+12"); +public static string TimezoneAbbreviations_UTC12=>T("TimezoneAbbreviations.UTC+12"); ///"FJST" -public static string TimezoneAbbriviations_Fiji_Standard_Time=>T("TimezoneAbbriviations.Fiji Standard Time"); +public static string TimezoneAbbreviations_Fiji_Standard_Time=>T("TimezoneAbbreviations.Fiji Standard Time"); ///"PETT" -public static string TimezoneAbbriviations_Kamchatka_Standard_Time=>T("TimezoneAbbriviations.Kamchatka Standard Time"); +public static string TimezoneAbbreviations_Kamchatka_Standard_Time=>T("TimezoneAbbreviations.Kamchatka Standard Time"); ///"CHAST" -public static string TimezoneAbbriviations_Chatham_Islands_Standard_Time=>T("TimezoneAbbriviations.Chatham Islands Standard Time"); +public static string TimezoneAbbreviations_Chatham_Islands_Standard_Time=>T("TimezoneAbbreviations.Chatham Islands Standard Time"); ///"TOT" -public static string TimezoneAbbriviations_Tonga_Standard_Time=>T("TimezoneAbbriviations.Tonga Standard Time"); +public static string TimezoneAbbreviations_Tonga_Standard_Time=>T("TimezoneAbbreviations.Tonga Standard Time"); ///"WSDT" -public static string TimezoneAbbriviations_Samoa_Standard_Time=>T("TimezoneAbbriviations.Samoa Standard Time"); +public static string TimezoneAbbreviations_Samoa_Standard_Time=>T("TimezoneAbbreviations.Samoa Standard Time"); ///"LINT" -public static string TimezoneAbbriviations_Line_Islands_Standard_Time=>T("TimezoneAbbriviations.Line Islands Standard Time"); +public static string TimezoneAbbreviations_Line_Islands_Standard_Time=>T("TimezoneAbbreviations.Line Islands Standard Time"); private static string T(string key) { - return StringResourceSystemFacade.GetString("Composite.Plugins.TimezoneAbbriviations", key); + return StringResourceSystemFacade.GetString("Composite.Plugins.TimezoneAbbreviations", key); } } diff --git a/Composite/Core/Routing/PageUrlData.cs b/Composite/Core/Routing/PageUrlData.cs index 66f2661fd5..6d6f7bb3b7 100644 --- a/Composite/Core/Routing/PageUrlData.cs +++ b/Composite/Core/Routing/PageUrlData.cs @@ -26,6 +26,7 @@ public PageUrlData(IPage page) Verify.ArgumentNotNull(page, "page"); PageId = page.Id; + VersionId = page.VersionId; this.PublicationScope = page.DataSourceId.PublicationScope; this.LocalizationScope = page.DataSourceId.LocaleScope; } @@ -53,6 +54,14 @@ public PageUrlData(Guid pageId, PublicationScope publicationScope, CultureInfo l /// public Guid PageId { get; set; } + /// + /// Gets or sets the page version id. + /// + /// + /// The page id. + /// + public Guid? VersionId { get; set; } + /// /// Gets or sets the publication scope. diff --git a/Composite/Core/Serialization/CodeGeneration/Foundation/ISerializer.cs b/Composite/Core/Serialization/CodeGeneration/Foundation/ISerializer.cs index 52e000b204..5be8274b46 100644 --- a/Composite/Core/Serialization/CodeGeneration/Foundation/ISerializer.cs +++ b/Composite/Core/Serialization/CodeGeneration/Foundation/ISerializer.cs @@ -11,7 +11,7 @@ namespace Composite.Core.Serialization.CodeGeneration.Foundation public interface ISerializer { /// - void Serialize(object propertyClass, StringBuilder serializedValues); + void Serialize(object propertyClass, StringBuilder serializedValues, IEnumerable propertyNames=null); /// object Deserialize(Dictionary objectState); diff --git a/Composite/Core/Serialization/CodeGeneration/PropertySerializerTypeCodeGenerator.cs b/Composite/Core/Serialization/CodeGeneration/PropertySerializerTypeCodeGenerator.cs index 19334030ae..bc2b127850 100644 --- a/Composite/Core/Serialization/CodeGeneration/PropertySerializerTypeCodeGenerator.cs +++ b/Composite/Core/Serialization/CodeGeneration/PropertySerializerTypeCodeGenerator.cs @@ -97,6 +97,7 @@ private static void AddSerializeMethod(CodeTypeDeclaration declaration, string p method.Attributes = MemberAttributes.Public | MemberAttributes.Final; method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "propertyClass")); method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(StringBuilder), "serializedValues")); + method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(IEnumerable), "propertyNames")); method.Statements.Add(new CodeVariableDeclarationStatement( @@ -150,7 +151,7 @@ private static void AddSerializeMethod(CodeTypeDeclaration declaration, string p ) )); } - + Type propertyType; string methodName; if (!property.Item2.IsArray) @@ -179,7 +180,7 @@ private static void AddSerializeMethod(CodeTypeDeclaration declaration, string p new CodePropertyReferenceExpression( new CodeVariableReferenceExpression("classToSerialize"), property.Item1 - ) + ),new CodeVariableReferenceExpression("propertyNames") } ) )); diff --git a/Composite/Core/Serialization/ISerializerHandler.cs b/Composite/Core/Serialization/ISerializerHandler.cs index edd77306e6..ab742d299f 100644 --- a/Composite/Core/Serialization/ISerializerHandler.cs +++ b/Composite/Core/Serialization/ISerializerHandler.cs @@ -1,8 +1,22 @@ namespace Composite.Core.Serialization { - internal interface ISerializerHandler + /// + /// Handler to serialize and deserialize data for use in Workflows during ie. postbacks. + /// + public interface ISerializerHandler { + /// + /// Returns a string representation of an object + /// + /// + /// string Serialize(object objectToSerialize); + + /// + /// Returns the constructed object deserialized from the passed string + /// + /// + /// object Deserialize(string serializedObject); } } diff --git a/Composite/Core/Serialization/SerializationFacade.cs b/Composite/Core/Serialization/SerializationFacade.cs index 8544dc7b3c..e3ed0aeb5c 100644 --- a/Composite/Core/Serialization/SerializationFacade.cs +++ b/Composite/Core/Serialization/SerializationFacade.cs @@ -35,7 +35,16 @@ public static string Serialize(object propertyClass) return sb.ToString(); } + public static string Serialize(object propertyClass, IEnumerable propertyNames) + { + ISerializer serializer = GetSerializer(propertyClass.GetType()); + + StringBuilder sb = new StringBuilder(); + serializer.Serialize(propertyClass, sb, propertyNames); + + return sb.ToString(); + } public static object Deserialize(Type propertyClassType, string serializedProperties) { diff --git a/Composite/Core/Serialization/SerializerHandlerAttribute.cs b/Composite/Core/Serialization/SerializerHandlerAttribute.cs index 815bdab3a2..2f0ac8a635 100644 --- a/Composite/Core/Serialization/SerializerHandlerAttribute.cs +++ b/Composite/Core/Serialization/SerializerHandlerAttribute.cs @@ -1,17 +1,25 @@ using System; - namespace Composite.Core.Serialization { + /// + /// Defines which is used to serialize and deserialize this class + /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, Inherited = false)] - internal sealed class SerializerHandlerAttribute : Attribute + public sealed class SerializerHandlerAttribute : Attribute { + /// + /// Defines which is used to serialize and deserialize this class + /// + /// public SerializerHandlerAttribute(Type serializerHandlerType) { this.SerializerHandlerType = serializerHandlerType; } - + /// + /// The type which is used to serialize and deserialize the class the attribute is added to + /// public Type SerializerHandlerType { get; private set; } } } diff --git a/Composite/Core/Serialization/StringConversionServices.cs b/Composite/Core/Serialization/StringConversionServices.cs index 93a0067167..b33c1081fe 100644 --- a/Composite/Core/Serialization/StringConversionServices.cs +++ b/Composite/Core/Serialization/StringConversionServices.cs @@ -87,6 +87,13 @@ public static void SerializeKeyValuePair(StringBuilder builder, string prope builder.Append(_unencodedValueMarker); } + /// + public static void SerializeKeyValuePair(StringBuilder builder, string propertyName, PT propertyValue, IEnumerable filterProperties) + { + if (filterProperties != null && !filterProperties.Contains(propertyName)) + return; + SerializeKeyValuePair(builder, propertyName, propertyValue); + } /// public static void SerializeKeyValuePair(StringBuilder builder, string propertyName, int propertyValue) @@ -443,6 +450,13 @@ public static void SerializeKeyValueArrayPair(StringBuilder builder, string } } + /// + public static void SerializeKeyValueArrayPair(StringBuilder builder, string propertyName, PT[] propertyValue,IEnumerable filterProperties) + { + if (filterProperties != null && !filterProperties.Contains(propertyName)) + return; + SerializeKeyValueArrayPair(builder, propertyName, propertyValue); + } /// public static PT[] DeserializeValueArray(string stringRepresentation, PT[] deserializationTarget) diff --git a/Composite/Core/Threading/ThreadDataManager.cs b/Composite/Core/Threading/ThreadDataManager.cs index c086d4c0ba..526ea1ce70 100644 --- a/Composite/Core/Threading/ThreadDataManager.cs +++ b/Composite/Core/Threading/ThreadDataManager.cs @@ -14,7 +14,7 @@ public static class ThreadDataManager private const string c_HttpContextItemsId = "ThreadDataManager"; [ThreadStatic] - private static ThreadDataManagerData _threadDataManagerData = null; + private static ThreadDataManagerData _threadDataManagerData; /// /// Gets object for the current thread @@ -88,10 +88,7 @@ public static ThreadDataManagerData GetCurrentNotNull() public static ThreadDataManagerData CreateNew() { var current = Current; - if(current != null) - { - current.CheckNotDisposed(); - } + current?.CheckNotDisposed(); return new ThreadDataManagerData(current); } @@ -111,10 +108,7 @@ public static IDisposable Initialize() [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public static IDisposable Initialize(ThreadDataManagerData parentThreadData) { - if(parentThreadData != null) - { - parentThreadData.CheckNotDisposed(); - } + parentThreadData?.CheckNotDisposed(); return new ThreadDataManagerScope(new ThreadDataManagerData(parentThreadData), true); } @@ -261,7 +255,7 @@ public void Dispose() } catch(Exception e) { - Core.Logging.LoggingService.LogError(LogTitle, e); + Log.LogError(LogTitle, e); } Verify.IsTrue(Current == _threadData, "ThreadDataManager.Current points to a different thread data object!!!"); diff --git a/Composite/Core/Types/CodeGenerationManager.cs b/Composite/Core/Types/CodeGenerationManager.cs index 778c87d1b8..92e4eb3074 100644 --- a/Composite/Core/Types/CodeGenerationManager.cs +++ b/Composite/Core/Types/CodeGenerationManager.cs @@ -393,7 +393,9 @@ internal static string BinFolder { get { - return Path.Combine(PathUtil.BaseDirectory, "Bin"); + return RuntimeInformation.IsUnittest + ? PathUtil.BaseDirectory + : Path.Combine(PathUtil.BaseDirectory, "Bin"); } } diff --git a/Composite/Core/WebClient/ApplicationLevelEventHandlers.cs b/Composite/Core/WebClient/ApplicationLevelEventHandlers.cs index 3d863ec4ae..04d1027266 100644 --- a/Composite/Core/WebClient/ApplicationLevelEventHandlers.cs +++ b/Composite/Core/WebClient/ApplicationLevelEventHandlers.cs @@ -15,6 +15,7 @@ using Composite.Core.Routing; using Composite.Core.Threading; using Composite.Core.Types; +using Composite.Data.Types; using Composite.Functions; using Composite.Plugins.Elements.UrlToEntityToken; using Composite.Plugins.Routing.InternalUrlConverters; @@ -100,6 +101,8 @@ private static void InitializeServices() InternalUrls.Register(new MediaInternalUrlConverter()); InternalUrls.Register(new PageInternalUrlConverter()); + + VersionedDataHelper.Initialize(); } diff --git a/Composite/Core/WebClient/FlowMediators/FormFlowRendering/FormFlowUiDefinitionRenderer.cs b/Composite/Core/WebClient/FlowMediators/FormFlowRendering/FormFlowUiDefinitionRenderer.cs index d1328e2dd2..4af3c8d67d 100644 --- a/Composite/Core/WebClient/FlowMediators/FormFlowRendering/FormFlowUiDefinitionRenderer.cs +++ b/Composite/Core/WebClient/FlowMediators/FormFlowRendering/FormFlowUiDefinitionRenderer.cs @@ -96,7 +96,9 @@ public static IUiControl Render( IUiControl customToolbarItems = null; if (customToolbarItemsMarkupProvider != null) { - FormTreeCompiler toolbarCompiler = new FormTreeCompiler(); + var toolbarCompiler = new FormTreeCompiler(); + CurrentCustomToolbarFormTreeCompiler = toolbarCompiler; + using (XmlReader formMarkupReader = customToolbarItemsMarkupProvider.GetReader()) { toolbarCompiler.Compile(formMarkupReader, channel, innerFormBindings, debugMode, bindingsValidationRules); @@ -115,7 +117,7 @@ public static IUiControl Render( string labelField = GetFormLabelField(document); ResourceHandle containerIcon = formCompiler.Icon; - return renderingContainer.Render(formCompiler.UiControl, customToolbarItems, channel, containerEventHandlerStubs, label, labelField, containerIcon); + return renderingContainer.Render(formCompiler.UiControl, customToolbarItems, channel, containerEventHandlerStubs, label, labelField, formCompiler.Tooltip, containerIcon); } private static void BaseEventHandler(string consoleId, @@ -133,6 +135,16 @@ private static void BaseEventHandler(string consoleId, FormFlowEventHandler handler = eventHandlers[localScopeEventIdentifier]; Dictionary bindingErrors = activeFormTreeCompiler.SaveAndValidateControlProperties(); + FormTreeCompiler activeCustomToolbarFormTreeCompiler = CurrentCustomToolbarFormTreeCompiler; + if (activeCustomToolbarFormTreeCompiler != null) + { + var toolbarBindingErrors = activeCustomToolbarFormTreeCompiler.SaveAndValidateControlProperties(); + foreach (var pair in toolbarBindingErrors) + { + bindingErrors.Add(pair.Key, pair.Value); + } + } + formServicesContainer.AddService(new BindingValidationService(bindingErrors)); handler.Invoke(flowToken, activeInnerFormBindings, formServicesContainer); @@ -143,7 +155,7 @@ private static void BaseEventHandler(string consoleId, return; } - var formFlowService = (FormFlowRenderingService) formServicesContainer.GetService(); + var formFlowService = formServicesContainer.GetService(); bool replacePageOutput = (formServicesContainer.GetService().NewPageOutput != null); bool rerenderView = formFlowService.RerenderViewRequested; @@ -237,17 +249,10 @@ private static void BaseEventHandler(string consoleId, private static string GetFormLabelField(XDocument formMarkup) { - var labelElement = formMarkup.Descendants(Namespaces.BindingForms10 + "layout.label").FirstOrDefault(); - if (labelElement == null) - { - labelElement = formMarkup.Descendants().FirstOrDefault(e => e.Name.LocalName == "TabPanels.Label"); - } - - if (labelElement == null) return null; - - + var labelElement = formMarkup.Descendants(Namespaces.BindingForms10 + "layout.label").FirstOrDefault() + ?? formMarkup.Descendants().FirstOrDefault(e => e.Name.LocalName == "TabPanels.Label"); - var readBinding = labelElement.Element(Namespaces.BindingForms10 + "read"); + var readBinding = labelElement?.Element(Namespaces.BindingForms10 + "read"); if(readBinding == null) return null; return (string)readBinding.Attribute("source"); @@ -261,6 +266,7 @@ private static IUiContainer GetRenderingContainer(IFormChannelIdentifier channel private static readonly string _formTreeCompilerLookupKey = typeof(FormFlowUiDefinitionRenderer).FullName + "FormTreeCompiler"; + private static readonly string _customToolbarFormTreeCompilerLookupKey = typeof(FormFlowUiDefinitionRenderer).FullName + "CustomToolbarFormTreeCompiler"; private static readonly string _innerFormBindingsLookupKey = typeof(FormFlowUiDefinitionRenderer).FullName + "InnerFormBindings"; private static readonly string _currentControlTreeRoot = typeof(FormFlowUiDefinitionRenderer).FullName + "ControlTreeRoot"; private static readonly string _currentControlContainer = typeof(FormFlowUiDefinitionRenderer).FullName + "ControlContainer"; @@ -273,6 +279,12 @@ private static FormTreeCompiler CurrentFormTreeCompiler set { HttpContext.Current.Items[_formTreeCompilerLookupKey] = value; } } + private static FormTreeCompiler CurrentCustomToolbarFormTreeCompiler + { + get { return HttpContext.Current.Items[_customToolbarFormTreeCompilerLookupKey] as FormTreeCompiler; } + set { HttpContext.Current.Items[_customToolbarFormTreeCompilerLookupKey] = value; } + } + private static Dictionary CurrentInnerFormBindings { get { return HttpContext.Current.Items[_innerFormBindingsLookupKey] as Dictionary; } @@ -295,11 +307,11 @@ private static IWebUiContainer CurrentControlContainer private static void ShowFieldMessages(IWebUiControl webUiControlTreeRoot, Dictionary bindingPathedMessages, IWebUiContainer container, FlowControllerServicesContainer servicesContainer) { - Dictionary pathToClientIDMappings = new Dictionary(); - ResolveBindingPathToCliendIDMappings(webUiControlTreeRoot, pathToClientIDMappings); + var pathToClientIDMappings = new Dictionary(); + ResolveBindingPathToClientIDMappings(webUiControlTreeRoot, pathToClientIDMappings); - Dictionary cliendIDPathedMessages = new Dictionary(); - Dictionary homelessMessages = new Dictionary(); + var cliendIDPathedMessages = new Dictionary(); + var homelessMessages = new Dictionary(); foreach (var msgElement in bindingPathedMessages) { @@ -332,14 +344,14 @@ private static void ShowFieldMessages(IWebUiControl webUiControlTreeRoot, Dictio } - internal static void ResolveBindingPathToCliendIDMappings(IWebUiControl webUiControl, Dictionary resolvedMappings) + internal static void ResolveBindingPathToClientIDMappings(IWebUiControl webUiControl, Dictionary resolvedMappings) { - if (webUiControl is ContainerUiControlBase) + var container = webUiControl as ContainerUiControlBase; + if (container != null) { - ContainerUiControlBase container = (ContainerUiControlBase)webUiControl; foreach (IUiControl child in container.UiControls) { - ResolveBindingPathToCliendIDMappings((IWebUiControl)child, resolvedMappings); + ResolveBindingPathToClientIDMappings((IWebUiControl)child, resolvedMappings); } } diff --git a/Composite/Core/WebClient/FlowMediators/WebFlowUiMediator.cs b/Composite/Core/WebClient/FlowMediators/WebFlowUiMediator.cs index 0b2d57d7e2..cd75d99851 100644 --- a/Composite/Core/WebClient/FlowMediators/WebFlowUiMediator.cs +++ b/Composite/Core/WebClient/FlowMediators/WebFlowUiMediator.cs @@ -7,7 +7,8 @@ using Composite.C1Console.Forms.Flows; using Composite.C1Console.Forms.WebChannel; using Composite.Core.WebClient.FlowMediators.FormFlowRendering; - +using System.Linq; +using System.Web.UI.HtmlControls; namespace Composite.Core.WebClient.FlowMediators { @@ -43,6 +44,17 @@ public static Control GetFlowUi(FlowHandle flowHandle, string elementProviderNam webControl = webForm.BuildWebControl(); if (string.IsNullOrEmpty(webControl.ID)) webControl.ID = "FlowUI"; + + if (RuntimeInformation.IsTestEnvironment) + { + var testAutomationLocatorInformation = formFlowUiDefinition.MarkupProvider as ITestAutomationLocatorInformation; + if (testAutomationLocatorInformation != null) { + var htmlform = webControl.Controls.OfType().FirstOrDefault(); + if (htmlform != null) { + htmlform.Attributes.Add("data-qa", testAutomationLocatorInformation.TestAutomationLocator); + } + } + } } return webControl; diff --git a/Composite/Core/WebClient/HttpModules/AdministrativeDataScopeSetterHttpModule.cs b/Composite/Core/WebClient/HttpModules/AdministrativeDataScopeSetterHttpModule.cs index afbaaf36ee..c2cb5bae39 100644 --- a/Composite/Core/WebClient/HttpModules/AdministrativeDataScopeSetterHttpModule.cs +++ b/Composite/Core/WebClient/HttpModules/AdministrativeDataScopeSetterHttpModule.cs @@ -10,39 +10,36 @@ namespace Composite.Core.WebClient.HttpModules { internal class AdministrativeDataScopeSetterHttpModule : IHttpModule { + private const string HttpContextItemsKey = nameof(AdministrativeDataScopeSetterHttpModule) + ":DataScope"; + public void Init(HttpApplication context) { - var moduleInstance = new ModuleInstance(); - context.AuthenticateRequest += moduleInstance.AuthenticateRequest; - context.EndRequest += moduleInstance.EndRequest; + context.AuthenticateRequest += AuthenticateRequest; + context.EndRequest += EndRequest; } - private class ModuleInstance + private static void AuthenticateRequest(object sender, EventArgs e) { - private DataScope _dataScope; - - public void AuthenticateRequest(object sender, EventArgs e) - { - if (SystemSetupFacade.IsSystemFirstTimeInitialized == false) return; + if (!SystemSetupFacade.IsSystemFirstTimeInitialized) return; - HttpApplication application = (HttpApplication)sender; - HttpContext context = application.Context; + HttpContext context = ((HttpApplication)sender).Context; - bool adminRootRequest = UrlUtils.IsAdminConsoleRequest(context); - - if (adminRootRequest && UserValidationFacade.IsLoggedIn()) - { - _dataScope = new DataScope(DataScopeIdentifier.Administrated, UserSettings.ActiveLocaleCultureInfo); - } - } + bool adminRootRequest = UrlUtils.IsAdminConsoleRequest(context); - public void EndRequest(object sender, EventArgs e) + if (adminRootRequest && UserValidationFacade.IsLoggedIn()) { - if (_dataScope != null) - { - _dataScope.Dispose(); - } + var dataScope = new DataScope(DataScopeIdentifier.Administrated, UserSettings.ActiveLocaleCultureInfo); + context.Items[HttpContextItemsKey] = dataScope; } + + } + + private static void EndRequest(object sender, EventArgs e) + { + HttpContext context = ((HttpApplication)sender).Context; + var dataScope = context.Items[HttpContextItemsKey] as DataScope; + + dataScope?.Dispose(); } public void Dispose() diff --git a/Composite/Core/WebClient/Renderings/RenderingContext.cs b/Composite/Core/WebClient/Renderings/RenderingContext.cs index 451bdfabd4..f349517b85 100644 --- a/Composite/Core/WebClient/Renderings/RenderingContext.cs +++ b/Composite/Core/WebClient/Renderings/RenderingContext.cs @@ -116,7 +116,7 @@ public bool RunResponseHandlers() public IEnumerable GetPagePlaceholderContents() { return PreviewMode ? (IEnumerable)HttpRuntime.Cache.Get(_previewKey + "_SelectedContents") - : PageManager.GetPlaceholderContent(PageRenderer.CurrentPage.Id); + : PageManager.GetPlaceholderContent(Page.Id, Page.VersionId); } diff --git a/Composite/Core/WebClient/Services/ConsoleMessageService/ActionTypeEnum.cs b/Composite/Core/WebClient/Services/ConsoleMessageService/ActionTypeEnum.cs index f8d4d49683..3f3c03372c 100644 --- a/Composite/Core/WebClient/Services/ConsoleMessageService/ActionTypeEnum.cs +++ b/Composite/Core/WebClient/Services/ConsoleMessageService/ActionTypeEnum.cs @@ -1,7 +1,7 @@ namespace Composite.Core.WebClient.Services.ConsoleMessageService { /// - [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public enum ActionType { /// @@ -56,6 +56,9 @@ public enum ActionType ExpandTreeNode = 15, /// - SelectElement = 16 + SelectElement = 16, + + /// + OpenSlideView = 18, } } diff --git a/Composite/Core/WebClient/Services/ConsoleMessageService/ConsoleAction.cs b/Composite/Core/WebClient/Services/ConsoleMessageService/ConsoleAction.cs index 81a8ca7b4d..ebe2ba34c6 100644 --- a/Composite/Core/WebClient/Services/ConsoleMessageService/ConsoleAction.cs +++ b/Composite/Core/WebClient/Services/ConsoleMessageService/ConsoleAction.cs @@ -32,6 +32,9 @@ public ConsoleAction() /// public OpenExternalViewParams OpenExternalViewParams { get; set; } + /// + public OpenSlideViewParams OpenSlideViewParams { get; set; } + /// public DownloadFileParams DownloadFileParams { get; set; } diff --git a/Composite/Core/WebClient/Services/ConsoleMessageService/ConsoleMessageServiceFacade.cs b/Composite/Core/WebClient/Services/ConsoleMessageService/ConsoleMessageServiceFacade.cs index 07b71a1f01..bcce78bf4c 100644 --- a/Composite/Core/WebClient/Services/ConsoleMessageService/ConsoleMessageServiceFacade.cs +++ b/Composite/Core/WebClient/Services/ConsoleMessageService/ConsoleMessageServiceFacade.cs @@ -15,7 +15,7 @@ namespace Composite.Core.WebClient.Services.ConsoleMessageService { /// - [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public static class ConsoleMessageServiceFacade { /// @@ -34,7 +34,7 @@ public static GetMessagesResult GetNewMessages(string consoleId, int lastKnownCh GetMessagesResult result = new GetMessagesResult(); result.CurrentSequenceNumber = ConsoleMessageQueueFacade.CurrentChangeNumber; - + List messageQueueElements = ConsoleMessageQueueFacade.GetQueueElements(lastKnownChangeNumber, consoleId).ToList(); if (messageQueueElements.Any() && messageQueueElements.Max(f => f.QueueItemNumber) > result.CurrentSequenceNumber) { @@ -169,7 +169,27 @@ public static GetMessagesResult GetNewMessages(string consoleId, int lastKnownCh ActionType = ActionType.OpenExternalView, OpenExternalViewParams = openExternalViewParams }); - } + } + + // Open slide views... + foreach (ConsoleMessageQueueElement queueElement in messageQueueElements.Where(f => f.QueueItem is OpenSlideViewQueueItem)) + { + var openSlideView = (OpenSlideViewQueueItem)queueElement.QueueItem; + + var openSlideViewParams = new OpenSlideViewParams + { + ViewId = openSlideView.ViewId, + EntityToken = openSlideView.EntityToken, + Url = openSlideView.Url + }; + + newMessages.Add(new ConsoleAction + { + SequenceNumber = queueElement.QueueItemNumber, + ActionType = ActionType.OpenSlideView, + OpenSlideViewParams = openSlideViewParams + }); + } // Download files... @@ -444,10 +464,10 @@ private static void DocumentSuspectMessageRequests(string consoleId, int lastKno private static string GetImage(ResourceHandle resourceHandle) { if (resourceHandle == null) return null; - + return string.Format("${{icon:{0}:{1}}}", resourceHandle.ResourceNamespace, resourceHandle.ResourceName); - + } } } diff --git a/Composite/Core/WebClient/Services/ConsoleMessageService/OpenSlideViewParams.cs b/Composite/Core/WebClient/Services/ConsoleMessageService/OpenSlideViewParams.cs new file mode 100644 index 0000000000..5e720ac1ab --- /dev/null +++ b/Composite/Core/WebClient/Services/ConsoleMessageService/OpenSlideViewParams.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using Composite.Core.Types; + + +namespace Composite.Core.WebClient.Services.ConsoleMessageService +{ + /// + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public class OpenSlideViewParams + { + /// + public string ViewId { get; set; } + /// + public string EntityToken { get; set; } + /// + public string Url { get; set; } + } +} diff --git a/Composite/Core/WebClient/Services/ConsoleMessageService/ViewTypeEnum.cs b/Composite/Core/WebClient/Services/ConsoleMessageService/ViewTypeEnum.cs index 66ecac6391..b4b7af26e3 100644 --- a/Composite/Core/WebClient/Services/ConsoleMessageService/ViewTypeEnum.cs +++ b/Composite/Core/WebClient/Services/ConsoleMessageService/ViewTypeEnum.cs @@ -3,7 +3,7 @@ namespace Composite.Core.WebClient.Services.ConsoleMessageService { /// - [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public enum ViewType { /// diff --git a/Composite/Core/WebClient/Services/TreeServiceObjects/ClientElement.cs b/Composite/Core/WebClient/Services/TreeServiceObjects/ClientElement.cs index 1ec3af2ad8..67bbc63d2a 100644 --- a/Composite/Core/WebClient/Services/TreeServiceObjects/ClientElement.cs +++ b/Composite/Core/WebClient/Services/TreeServiceObjects/ClientElement.cs @@ -73,5 +73,15 @@ public sealed class ClientElement /// the client should disregard elements with TreeLockEnabled == true and continue searching. /// public bool TreeLockEnabled { get; set; } + + /// + /// Having a common ElementBundle across elements will make the client bundle them up as a single node, and allow the user to select a specific element via a drop down, showing individual BundleElementName values + /// + public string ElementBundle { get; set; } + + /// + /// When bundling elements this field is used to identify this specific element for selection + /// + public string BundleElementName { get; set; } } } diff --git a/Composite/Core/WebClient/Services/TreeServiceObjects/ExtensionMethods/ElementExtensionMethods.cs b/Composite/Core/WebClient/Services/TreeServiceObjects/ExtensionMethods/ElementExtensionMethods.cs index ebd0d56e6b..ffdfd494dc 100644 --- a/Composite/Core/WebClient/Services/TreeServiceObjects/ExtensionMethods/ElementExtensionMethods.cs +++ b/Composite/Core/WebClient/Services/TreeServiceObjects/ExtensionMethods/ElementExtensionMethods.cs @@ -41,7 +41,9 @@ public static ClientElement GetClientElement(this Element element) PropertyBag = element.PropertyBag.ToClientPropertyBag(), TagValue = element.TagValue, ContainsTaggedActions = element.Actions.Any(f => f.TagValue != null), - TreeLockEnabled = element.TreeLockBehavior == TreeLockBehavior.Normal + TreeLockEnabled = element.TreeLockBehavior == TreeLockBehavior.Normal, + ElementBundle = element.VisualData.ElementBundle, + BundleElementName = element.VisualData.BundleElementName }; clientElement.ActionKeys = diff --git a/Composite/Core/WebClient/UiControlLib/ComboBox.cs b/Composite/Core/WebClient/UiControlLib/ComboBox.cs index 2ad68d4378..f90a9e4938 100644 --- a/Composite/Core/WebClient/UiControlLib/ComboBox.cs +++ b/Composite/Core/WebClient/UiControlLib/ComboBox.cs @@ -44,7 +44,7 @@ protected override void AddAttributesToRender(HtmlTextWriter writer) if (this.AutoPostBack) { - writer.AddAttribute("onchange", "this.dispatchAction(PageBinding.ACTION_DOPOSTBACK)"); + writer.AddAttribute("onselectionchange", "this.dispatchAction(PageBinding.ACTION_DOPOSTBACK)"); } if (this.SelectionRequired) { @@ -86,6 +86,11 @@ protected override void RenderContents(HtmlTextWriter writer) { for (int i = 0; i < this.Items.Count; i++) { + if (Items[i].Text == ReservedKey) + { + continue; + } + string label = StringResourceSystemFacade.ParseString(this.Items[i].Text); int firstNonSpaceSpacePosition = 0; @@ -105,7 +110,7 @@ protected override void RenderContents(HtmlTextWriter writer) foreach(ListItem item in items) { - if (!item.Enabled) + if (!item.Enabled || item.Text == ReservedKey) { continue; } diff --git a/Composite/Core/WebClient/UiControlLib/Foundation/ClientAttributes.cs b/Composite/Core/WebClient/UiControlLib/Foundation/ClientAttributes.cs index 3ed3207df2..95b5704281 100644 --- a/Composite/Core/WebClient/UiControlLib/Foundation/ClientAttributes.cs +++ b/Composite/Core/WebClient/UiControlLib/Foundation/ClientAttributes.cs @@ -3,9 +3,9 @@ namespace Composite.Core.WebClient.UiControlLib.Foundation { - internal static class ClientAttributes + public static class ClientAttributes { - public static void WriteClientAttributes(this WebControl uiControl, HtmlTextWriter writer) + internal static void WriteClientAttributes(this WebControl uiControl, HtmlTextWriter writer) { foreach (string attributeName in uiControl.Attributes.Keys) { @@ -18,8 +18,7 @@ public static void WriteClientAttributes(this WebControl uiControl, HtmlTextWrit } } - - public static void AddClientAttributes(this WebControl uiControl, HtmlTextWriter writer) + internal static void AddClientAttributes(this WebControl uiControl, HtmlTextWriter writer) { foreach (string attributeName in uiControl.Attributes.Keys) { @@ -32,5 +31,17 @@ public static void AddClientAttributes(this WebControl uiControl, HtmlTextWriter } } - } + public static void CopyClientAttributesTo(this UserControl uiControl, WebControl targetControl) + { + foreach (string attributeName in uiControl.Attributes.Keys) + { + string attributeNameLower = attributeName.ToLowerInvariant(); + if (attributeNameLower.StartsWith("client_")) + { + string clientAttributeName = attributeNameLower.Substring("client_".Length); + targetControl.Attributes[attributeName] = uiControl.Attributes[attributeName]; + } + } + } + } } diff --git a/Composite/Core/WebClient/UiControlLib/ToolbarButton.cs b/Composite/Core/WebClient/UiControlLib/ToolbarButton.cs index 1650aff210..f027ea9ea9 100644 --- a/Composite/Core/WebClient/UiControlLib/ToolbarButton.cs +++ b/Composite/Core/WebClient/UiControlLib/ToolbarButton.cs @@ -12,15 +12,15 @@ namespace Composite.Core.WebClient.UiControlLib public class ToolbarButton : LinkButton { /// - [Category("Behavior"), DefaultValue(""), Description("The id as the ui client should see")] + [Category("Behavior"), DefaultValue(""), Description("The id as the UI client should see")] public virtual string CustomClientId { get; set; } /// - [Category("Appearance"), DefaultValue(""), Description("Image to show in the buttom")] + [Category("Appearance"), DefaultValue(""), Description("Image to show on the button")] public virtual string ImageUrl { get; set; } /// - [Category("Appearance"), DefaultValue(""), Description("Image to show in the buttom when the button is disabled")] + [Category("Appearance"), DefaultValue(""), Description("Image to show on the button when it is disabled")] public virtual string ImageUrlWhenDisabled { get; set; } /// diff --git a/Composite/Data/Caching/CachingEnumerator.cs b/Composite/Data/Caching/CachingEnumerator.cs index 3f8a633825..eb7ae76991 100644 --- a/Composite/Data/Caching/CachingEnumerator.cs +++ b/Composite/Data/Caching/CachingEnumerator.cs @@ -8,8 +8,8 @@ namespace Composite.Data.Caching { internal sealed class CachingEnumerator : IEnumerator { - private IEnumerator _enumerator; - private Type _wrapperType; + private readonly IEnumerator _enumerator; + private Func _wrapperConstructor; public CachingEnumerator(IEnumerator enumerator) @@ -18,15 +18,7 @@ public CachingEnumerator(IEnumerator enumerator) } - public T Current - { - get - { - object wrapper = Activator.CreateInstance(this.WrapperType, new object[] { _enumerator.Current }); - - return (T)wrapper; - } - } + public T Current => WrapperConstructor(_enumerator.Current); public void Dispose() @@ -35,15 +27,7 @@ public void Dispose() } - object IEnumerator.Current - { - get - { - object wrapper = Activator.CreateInstance(this.WrapperType, new object[] { _enumerator.Current }); - - return wrapper; - } - } + object IEnumerator.Current => WrapperConstructor(_enumerator.Current); public bool MoveNext() @@ -58,16 +42,12 @@ public void Reset() } - private Type WrapperType + private Func WrapperConstructor { get { - if (_wrapperType == null) - { - _wrapperType = DataWrapperTypeManager.GetDataWrapperType(typeof(T)); - } - - return _wrapperType; + return _wrapperConstructor + ?? (_wrapperConstructor = DataWrapperTypeManager.GetWrapperConstructor()); } } } diff --git a/Composite/Data/Caching/CachingQueryable.cs b/Composite/Data/Caching/CachingQueryable.cs index 4d24a6394e..56b64655a4 100644 --- a/Composite/Data/Caching/CachingQueryable.cs +++ b/Composite/Data/Caching/CachingQueryable.cs @@ -4,10 +4,10 @@ using System.Linq; using System.Linq.Expressions; using System.Threading; -using Composite.Core.Collections.Generic; using Composite.Core.Types; using Composite.Data.Caching.Foundation; using System.Reflection; +using Composite.Core.Extensions; using Composite.Core.Linq; using Composite.Data.Foundation; @@ -47,6 +47,7 @@ internal interface ICachedQuery internal interface CachingQueryable_CachedByKey { IData GetCachedValueByKey(object key); + IEnumerable GetCachedVersionValuesByKey(object key); } @@ -57,8 +58,9 @@ internal sealed class CachingQueryable : ICachedQuery, IOrderedQueryable, private readonly CachingEnumerable _wrappedEnumerable; private readonly Func _getQueryFunc; - private readonly DataCachingFacade.CachedTable _cachedTable; + private volatile DataCachingFacade.CachedTable _cachedTable; private static readonly MethodInfo _wrappingMethodInfo; + private static readonly MethodInfo _listWrappingMethodInfo; private IEnumerable _innerEnumerable; @@ -69,7 +71,17 @@ static CachingQueryable() _wrappingMethodInfo = StaticReflection.GetGenericMethodInfo(a => DataWrappingFacade.Wrap((IData) a)) .MakeGenericMethod(new[] {typeof (T)}); } - } + if (typeof(IData).IsAssignableFrom(typeof(T))) + { + _listWrappingMethodInfo = StaticReflection.GetGenericMethodInfo(a => WrapData((IEnumerable)a)) + .MakeGenericMethod(typeof(T)); + } + } + + private static IEnumerable WrapData(IEnumerable input) where T : class, IData + { + return input.Select(DataWrappingFacade.Wrap); + } public CachingQueryable(DataCachingFacade.CachedTable cachedTable, Func originalQueryGetter) { @@ -202,66 +214,104 @@ public object Execute(Expression expression) public IData GetCachedValueByKey(object key) { - if (_cachedTable.RowByKey == null) - { - lock(_cachedTable) - { - if (_cachedTable.RowByKey == null) - { - var table = new Hashtable(); + var filteredData = GetFromCacheFiltered(key); + if (filteredData == null) return null; - PropertyInfo keyPropertyInfo = DataAttributeFacade.GetKeyProperties(typeof(T)).Single(); + var result = filteredData.FirstOrDefault(); + if (result == null) return null; - IEnumerable enumerable = BuildEnumerable(); + return _wrappingMethodInfo.Invoke(null, new object[] { result }) as IData; + } - var emptyIndexCollection = new object[0]; - foreach(T row in enumerable) - { - object rowKey = keyPropertyInfo.GetValue(row, emptyIndexCollection); + public IEnumerable GetCachedVersionValuesByKey(object key) + { + var result = GetFromCacheFiltered(key); + if (result == null) return Enumerable.Empty(); - table.Add(rowKey, row); - } + return _listWrappingMethodInfo.Invoke(null, new object[] { result }) as IEnumerable; + } - _cachedTable.RowByKey = table; - } - } + + private IEnumerable GetFromCacheFiltered(object key) + { + var cachedTable = GetRowsByKeyTable(); + IEnumerable cachedRows; + + if (!cachedTable.TryGetValue(key, out cachedRows)) + { + return null; } - object cachedRow = _cachedTable.RowByKey[key]; - if (cachedRow == null) return null; + IEnumerable filteredData = cachedRows.Cast(); - return _wrappingMethodInfo.Invoke(null, new object[] { cachedRow }) as IData; - } + var filterMethodInfo = StaticReflection.GetGenericMethodInfo( + () => ((DataInterceptor)null).InterceptGetData((IEnumerable)null)) + .MakeGenericMethod(typeof(T)); + foreach (var dataInterceptor in DataFacade.GetDataInterceptors(typeof(T))) + { + filteredData = (IEnumerable)filterMethodInfo.Invoke(dataInterceptor, new object[] { filteredData }); + } - public Expression Expression - { - get { return _currentExpression; } + return filteredData; } - - public Type ElementType + Dictionary> GetRowsByKeyTable() { - get { return typeof(T); } - } + var cachedTable = GetCachedTable(); + var result = cachedTable.RowsByKey; + if (result != null) + { + return result; + } + lock (cachedTable) + { + result = cachedTable.RowsByKey; + if (result != null) + { + return result; + } - public IQueryProvider Provider - { - get { return this; } - } + PropertyInfo keyPropertyInfo = typeof(T).GetKeyProperties().Single(); - public IQueryable Source - { - get { return _source; } + result = BuildEnumerable() + .GroupBy(data => keyPropertyInfo.GetValue(data, null)) + .ToDictionary(group => group.Key, group => group.ToArray() as IEnumerable); + + return cachedTable.RowsByKey = result; + } } - public IQueryable GetOriginalQuery() + + private DataCachingFacade.CachedTable GetCachedTable() { - return _getQueryFunc(); + if (_cachedTable == null) + { + lock (this) + { + if (_cachedTable == null) + { + _cachedTable = new DataCachingFacade.CachedTable(GetOriginalQuery()); + } + } + } + + return _cachedTable; } + + + public Expression Expression => _currentExpression; + + public Type ElementType => typeof(T); + + public IQueryProvider Provider => this; + + public IQueryable Source => _source; + + public IQueryable GetOriginalQuery() => _getQueryFunc(); } } diff --git a/Composite/Data/Caching/DataCachingFacade.cs b/Composite/Data/Caching/DataCachingFacade.cs index 9f4b5a5f19..08440397a3 100644 --- a/Composite/Data/Caching/DataCachingFacade.cs +++ b/Composite/Data/Caching/DataCachingFacade.cs @@ -65,21 +65,15 @@ public CachedTable(IQueryable queryable) /// /// Row by key table /// - public Hashtable RowByKey; + public Dictionary> RowsByKey; } /// /// Gets a value indicating if data caching is enabled /// - public static bool Enabled - { - get - { - return _isEnabled; - } - } + public static bool Enabled => _isEnabled; + - /// /// Gets a value indicating if data caching is possible for a specific data type /// @@ -111,7 +105,7 @@ public static bool IsDataAccessCacheEnabled(Type interfaceType) /// - internal static IQueryable GetDataFromCache() + internal static IQueryable GetDataFromCache(Func> getQueryFunc) where T : class, IData { Verify.That(_isEnabled, "The cache is disabled."); @@ -151,7 +145,7 @@ internal static IQueryable GetDataFromCache() CachedTable cachedTable; if (!localizationScopeData.TryGetValue(localizationScope, out cachedTable)) { - IQueryable wholeTable = DataFacade.GetData(false, null); + IQueryable wholeTable = getQueryFunc(); if(!DataProvidersSupportDataWrapping(typeof(T))) { @@ -194,7 +188,7 @@ internal static IQueryable GetDataFromCache() { using (new DataScope(dataScopeIdentifier, localizationScope)) { - return DataFacade.GetData(false); + return getQueryFunc(); } }; @@ -303,7 +297,7 @@ private static MethodInfo GetQueryableTakeMethodInfo(Type type) if(_queryableTakeMathodInfo == null) { _queryableTakeMathodInfo = (from method in typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public) - where method.Name == "Take" && + where method.Name == nameof(Queryable.Take) && method.IsGenericMethod select method).First(); } diff --git a/Composite/Data/DataAttributeFacade.cs b/Composite/Data/DataAttributeFacade.cs index a11ef7580c..8db2e95f93 100644 --- a/Composite/Data/DataAttributeFacade.cs +++ b/Composite/Data/DataAttributeFacade.cs @@ -6,8 +6,10 @@ using Composite.Core; using Composite.Core.Collections.Generic; using Composite.C1Console.Events; +using Composite.Core.Linq; using Composite.Core.ResourceSystem; using Composite.Core.Types; +using Composite.Data.Types; namespace Composite.Data @@ -359,17 +361,16 @@ public static IReadOnlyList GetDataReferenceProperties(Type { if (attr.InterfaceType == null) { - throw new InvalidOperationException(string.Format("Null argument is not allowed for the attribute '{0}' on the property '{1}'", - typeof(ForeignKeyAttribute), propertyInfo)); + throw new InvalidOperationException( + $"Null argument is not allowed for the attribute '{typeof (ForeignKeyAttribute)}' on the property '{propertyInfo}'"); } if (!typeof (IData).IsAssignableFrom(attr.InterfaceType)) { - throw new InvalidOperationException(string.Format("The argument should inherit the type '{0}' for the attribute '{1}' on the property '{2}'", - typeof(IData), typeof(ForeignKeyAttribute), propertyInfo)); + throw new InvalidOperationException( + $"The argument should inherit the type '{typeof (IData)}' for the attribute '{typeof (ForeignKeyAttribute)}' on the property '{propertyInfo}'"); } - if (attr.IsNullReferenceValueSet) { @@ -421,6 +422,19 @@ orderby kpn.Index } + /// + public static IReadOnlyList GetVersionKeyPropertyNames(this Type interfaceType) + { + Verify.ArgumentNotNull(interfaceType, "interfaceType"); + + var map = _resourceLocker.Resources.InterfaceTypeToVersionKeyPropertyNames; + + return map.GetOrAdd(interfaceType, type => + (from kpn in type.GetCustomAttributesRecursively() + orderby kpn.VersionKeyPropertyName + select kpn.VersionKeyPropertyName).ToList()); + } + /// [Obsolete("Use GetKeyProperties() instead")] public static List GetKeyPropertyInfoes(this IData data) @@ -446,12 +460,29 @@ public static List GetKeyPropertyInfoes(this Type interfaceType) return new List(GetKeyProperties(interfaceType)); } + /// + public static IReadOnlyList GetPhysicalKeyProperties(this Type interfaceType) + { + var versionKeyAttributes = interfaceType + .GetCustomAttributesRecursively(); + + var versionProperties = versionKeyAttributes + .Select(v => interfaceType.GetDataPropertyRecursively(v.VersionKeyPropertyName)); + + var keyProperties = GetKeyProperties(interfaceType); + + return keyProperties.Concat(versionProperties).ToList(); + } + /// public static IReadOnlyList GetKeyProperties(this Type interfaceType) { Verify.ArgumentNotNull(interfaceType, "interfaceType"); - if (!typeof(IData).IsAssignableFrom(interfaceType)) throw new ArgumentException(string.Format("The specified type must inherit from '{0}", typeof(IData))); + if (!typeof(IData).IsAssignableFrom(interfaceType)) + { + throw new ArgumentException($"The specified type must inherit from '{typeof (IData)}"); + } var map = _resourceLocker.Resources.InterfaceTypeToKeyPropertyInfo; @@ -475,6 +506,12 @@ public static IReadOnlyList GetKeyProperties(this Type interfaceTy }); } + internal static PropertyInfo GetSingleKeyProperty(this Type interfaceType) + { + return interfaceType.GetKeyProperties().SingleOrException( + "No key properties defined on data type '{0}'", + "Multiple key proterties defined for data type '{0}'", interfaceType); + } /// @@ -491,7 +528,7 @@ public static string GetTypeTitle(this IData data) public static string GetTypeTitle(this Type interfaceType) { if (interfaceType == null) throw new ArgumentNullException("interfaceType"); - if (typeof(IData).IsAssignableFrom(interfaceType) == false) throw new ArgumentException(string.Format("The specified type must inherit from '{0}", typeof(IData))); + if (!typeof(IData).IsAssignableFrom(interfaceType)) throw new ArgumentException($"The specified type must inherit from '{typeof (IData)}"); string title; @@ -511,7 +548,8 @@ public static string GetTypeTitle(this Type interfaceType) } else { - throw new InvalidOperationException(string.Format("More than one '{0}' defined on the type '{1}'", typeof(TitleAttribute), interfaceType)); + throw new InvalidOperationException( + $"More than one '{typeof (TitleAttribute)}' defined on the type '{interfaceType}'"); } _resourceLocker.Resources.InterfaceTypeToTypeTitle.Add(interfaceType, title); @@ -550,6 +588,7 @@ private sealed class Resources public ConcurrentDictionary> InterfaceTypeToKeyPropertyInfo { get; set; } public Dictionary InterfaceTypeToTypeTitle { get; set; } public ConcurrentDictionary> InterfaceTypeToKeyPropertyNames { get; set; } + public ConcurrentDictionary> InterfaceTypeToVersionKeyPropertyNames { get; set; } public static void Initialize(Resources resources) { @@ -565,6 +604,7 @@ public static void Initialize(Resources resources) resources.InterfaceTypeToKeyPropertyInfo = new ConcurrentDictionary>(); resources.InterfaceTypeToTypeTitle = new Dictionary(); resources.InterfaceTypeToKeyPropertyNames = new ConcurrentDictionary>(); + resources.InterfaceTypeToVersionKeyPropertyNames = new ConcurrentDictionary>(); } } } diff --git a/Composite/Data/DataConnection.cs b/Composite/Data/DataConnection.cs index dcb6b26836..f0a3f850a3 100644 --- a/Composite/Data/DataConnection.cs +++ b/Composite/Data/DataConnection.cs @@ -25,9 +25,37 @@ namespace Composite.Data public class DataConnection : ImplementationContainer, IDisposable { //private ImplementationContainer _pageDataConnection; - private ImplementationContainer _sitemapNavigator; + private readonly ImplementationContainer _sitemapNavigator; + private bool _disposed; + + /// + /// Resolve service of a specific type that is attached to connection's data scope + /// + /// + /// + public object GetService(Type t) + { + return ImplementationFactory.CurrentFactory.ResolveService(t); + } + + /// + /// attach service to data connection + /// + /// + public void AddService(object service) + { + Implementation.DataScope.AddService(service); + } + + /// + /// disable all services in the data connection + /// + public void DisableServices() + { + Implementation.DataScope.DisableServices(); + } /// /// Creates a new instance inheriting the @@ -503,12 +531,18 @@ public void Dispose() /// protected virtual void Dispose(bool disposing) { - if (disposing) + if (!disposing) return; + + if (_disposed) { - this.DisposeImplementation(); - //_pageDataConnection.Implementation.DisposeImplementation(); - _sitemapNavigator.Implementation.DisposeImplementation(); + throw new ObjectDisposedException(nameof(DataConnection)); } + + this.DisposeImplementation(); + + _sitemapNavigator.Implementation.DisposeImplementation(); + + _disposed = true; } } } diff --git a/Composite/Data/DataEntityToken.cs b/Composite/Data/DataEntityToken.cs index 6f6b7e70fe..b0454bbc77 100644 --- a/Composite/Data/DataEntityToken.cs +++ b/Composite/Data/DataEntityToken.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Reflection; using System.Text; using Composite.C1Console.Security; @@ -17,10 +18,11 @@ public sealed class DataEntityToken : EntityToken private IData _data; private bool _dataInitialized; private string _serializedDataSourceId; - private string _serializedDataId = null; - private string _serializedInterfaceType = null; - private Type _interfaceType = null; - private DataSourceId _dataSourceId = null; + private string _serializedId; + private string _serializedVersionId; + private string _serializedInterfaceType; + private Type _interfaceType; + private DataSourceId _dataSourceId; internal DataEntityToken(IData data) @@ -28,7 +30,7 @@ internal DataEntityToken(IData data) Verify.ArgumentNotNull(data, "data"); _data = data; - _dataInitialized = true; + _dataInitialized = true; _serializedDataSourceId = null; _dataSourceId = _data.DataSourceId; Verify.ArgumentCondition(_dataSourceId != null, "data", "DataSourceId can not be null"); @@ -65,23 +67,14 @@ public override string Type /// - public override string Source - { - get - { - return this.DataSourceId.ProviderName; - } - } - + public override string Source => this.DataSourceId.ProviderName; /// - public override string Id - { - get { return this.SerializedDataId; } - } - + public override string Id => this.SerializedId; + /// + public override string VersionId => this.SerializedVersionId; /// public override bool IsValid() @@ -155,7 +148,7 @@ public IData Data { get { - if (_dataInitialized == false) + if (!_dataInitialized) { try { @@ -184,9 +177,9 @@ public override void OnGetPrettyHtml(EntityTokenHtmlPrettyfier prettyfier) { prettyfier.OnWriteId = (token, helper) => { - IDataId dataId = DataIdSerializer.Deserialize(this.Id); + IDataId dataId = DataIdSerializer.Deserialize(this.Id,this.VersionId); - StringBuilder sb = new StringBuilder(); + var sb = new StringBuilder(); sb.Append("DataId
"); sb.Append("Type: " + dataId.GetType() + "
"); foreach (PropertyInfo propertyInfo in dataId.GetType().GetPropertiesRecursively()) @@ -215,21 +208,36 @@ private string SerializedDataSourceId - private string SerializedDataId + private string SerializedId { get { - if (_serializedDataId == null) + if (_serializedId == null) { - _serializedDataId = this.DataSourceId.DataId.Serialize(); + var keyPropertyNames = this.InterfaceType.GetCustomAttributesRecursively().Select(f=>f.KeyPropertyName); + + _serializedId = this.DataSourceId.DataId.Serialize(keyPropertyNames); } - return _serializedDataId; + return _serializedId; } } + private string SerializedVersionId + { + get + { + if (_serializedVersionId == null) + { + var versionKeyPropertyNames = this.InterfaceType.GetCustomAttributesRecursively().Select(f=>f.VersionKeyPropertyName); + + _serializedVersionId = this.DataSourceId.DataId.Serialize(versionKeyPropertyNames); + } - + return _serializedVersionId; + } + } + private void CheckValidity() { Verify.That(IsValid(), "Failed to deserialize data from serialized data source identifier. Probably the data has been removed from data source."); diff --git a/Composite/Data/DataFacade.cs b/Composite/Data/DataFacade.cs index 72a17a9a54..67b5691d32 100644 --- a/Composite/Data/DataFacade.cs +++ b/Composite/Data/DataFacade.cs @@ -83,7 +83,7 @@ static DataFacade() GlobalEventSystemFacade.SubscribeToFlushEvent(OnFlushEvent); } - + internal static IDataFacade Implementation { get { return _dataFacade; } set { _dataFacade = value; } } @@ -128,6 +128,12 @@ public static bool HasDataInterceptor() } + /// + internal static IEnumerable GetDataInterceptors(Type interfaceType) + { + return _dataFacade.GetDataInterceptors(interfaceType); + } + // Overload /// @@ -162,6 +168,34 @@ public static void ClearDataInterceptor(Type interfaceType) methodInfo.Invoke(null, new object[] { }); } + /// + public static void SetGlobalDataInterceptor(DataInterceptor dataInterceptor) + where T : class, IData + { + _dataFacade.SetGlobalDataInterceptor(dataInterceptor); + } + + + + /// + public static bool HasGlobalDataInterceptor() + where T : class, IData + { + return _dataFacade.HasGlobalDataInterceptor(); + } + + + + /// + public static void ClearGlobalDataInterceptor() + where T : class, IData + { + _dataFacade.ClearGlobalDataInterceptor(); + } + + + + #endregion @@ -361,27 +395,35 @@ public static IEnumerable GetDataFromOtherScope(IData data, DataScopeIden } /// - public static IEnumerable GetDataFromOtherScope(IData data, DataScopeIdentifier dataScopeIdentifier, bool useCaching) + public static IEnumerable GetDataFromOtherScope( + IData data, DataScopeIdentifier dataScopeIdentifier, bool useCaching) + { + return GetDataFromOtherScope(data, dataScopeIdentifier, useCaching, true); + } + + /// + public static IEnumerable GetDataFromOtherScope( + IData data, DataScopeIdentifier dataScopeIdentifier, bool useCaching, bool ignoreVersioning) { Verify.ArgumentNotNull(data, "data"); - if (dataScopeIdentifier == null) throw new ArgumentNullException("dataScopeIdentifier"); + Verify.ArgumentNotNull(dataScopeIdentifier, nameof(dataScopeIdentifier)); - if (GetSupportedDataScopes(data.DataSourceId.InterfaceType).Contains(dataScopeIdentifier) == false) throw new ArgumentException(string.Format("The data type '{0}' does not support the data scope '{1}'", data.DataSourceId.InterfaceType, dataScopeIdentifier)); + if (!GetSupportedDataScopes(data.DataSourceId.InterfaceType).Contains(dataScopeIdentifier)) + { + throw new ArgumentException($"The data type '{data.DataSourceId.InterfaceType}' does not support the data scope '{dataScopeIdentifier}'"); + } if (useCaching) { DataSourceId sourceId = data.DataSourceId; - DataSourceId newDataSource = new DataSourceId(sourceId.DataId, sourceId.ProviderName, - sourceId.InterfaceType); + var newDataSource = new DataSourceId(sourceId.DataId, sourceId.ProviderName, sourceId.InterfaceType) + { + DataScopeIdentifier = dataScopeIdentifier + }; - newDataSource.DataScopeIdentifier = dataScopeIdentifier; IData fromDataSource = GetDataFromDataSourceId(newDataSource, true); - if (fromDataSource == null) - { - return new IData[0]; - } - return new[] { fromDataSource }; + return fromDataSource == null ? new IData[0] : new[] { fromDataSource }; } var result = new List(); @@ -390,7 +432,7 @@ public static IEnumerable GetDataFromOtherScope(IData data, DataScopeIden { IQueryable table = GetData(data.DataSourceId.InterfaceType, false); - IQueryable queryable = DataExpressionBuilder.GetQueryableByData(data, table, true); + IQueryable queryable = DataExpressionBuilder.GetQueryableByData(data, table, ignoreVersioning); foreach (object obj in queryable) { @@ -411,13 +453,13 @@ public static IEnumerable GetDataFromOtherScope(IData data, DataScopeIden public static Expression> GetPredicateExpressionByUniqueKey(DataKeyPropertyCollection dataKeyPropertyCollection) where T : class, IData { - if (dataKeyPropertyCollection == null) throw new ArgumentNullException("dataKeyPropertyCollection"); + Verify.ArgumentNotNull(dataKeyPropertyCollection, nameof(dataKeyPropertyCollection)); - var keyPropertyInfos = DataAttributeFacade.GetKeyProperties(typeof(T)); + var keyProperties = typeof(T).GetKeyProperties(); ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "data"); - Expression currentExpression = GetPredicateExpressionByUniqueKeyFilterExpression(keyPropertyInfos, dataKeyPropertyCollection, parameterExpression); + Expression currentExpression = GetPredicateExpressionByUniqueKeyFilterExpression(keyProperties, dataKeyPropertyCollection, parameterExpression); Expression> lambdaExpression = Expression.Lambda>(currentExpression, new ParameterExpression[] { parameterExpression }); @@ -471,7 +513,7 @@ public static LambdaExpression GetPredicateExpressionByUniqueKey(Type interfaceT PropertyInfo propertyInfo = DataAttributeFacade.GetKeyProperties(interfaceType).Single(); var dataKeyPropertyCollection = new DataKeyPropertyCollection(); - dataKeyPropertyCollection.AddKeyProperty(propertyInfo, dataKeyValue); + dataKeyPropertyCollection.AddKeyProperty(propertyInfo, dataKeyValue); return GetPredicateExpressionByUniqueKey(interfaceType, dataKeyPropertyCollection); } @@ -568,12 +610,34 @@ public static IData TryGetDataByUniqueKey(Type interfaceType, object dataKeyValu PropertyInfo propertyInfo = DataAttributeFacade.GetKeyProperties(interfaceType).Single(); DataKeyPropertyCollection dataKeyPropertyCollection = new DataKeyPropertyCollection(); - dataKeyPropertyCollection.AddKeyProperty(propertyInfo, dataKeyValue); + dataKeyPropertyCollection.AddKeyProperty(propertyInfo, dataKeyValue); return TryGetDataByUniqueKey(interfaceType, dataKeyPropertyCollection); } + // Overload + /// + public static IEnumerable TryGetDataVersionsByUniqueKey(Type interfaceType, object dataKeyValue) + { + Verify.ArgumentNotNull(interfaceType, "interfaceType"); + + if (DataCachingFacade.IsDataAccessCacheEnabled(interfaceType)) + { + var cachedByKey = DataFacade.GetData(interfaceType) as CachingQueryable_CachedByKey; + if (cachedByKey != null) + { + return cachedByKey.GetCachedVersionValuesByKey(dataKeyValue); + } + } + + PropertyInfo propertyInfo = DataAttributeFacade.GetKeyProperties(interfaceType).Single(); + + DataKeyPropertyCollection dataKeyPropertyCollection = new DataKeyPropertyCollection(); + dataKeyPropertyCollection.AddKeyProperty(propertyInfo, dataKeyValue); + + return TryGetDataVersionsByUniqueKey(interfaceType, dataKeyPropertyCollection); + } /// public static IData TryGetDataByUniqueKey(Type interfaceType, DataKeyPropertyCollection dataKeyPropertyCollection) @@ -592,7 +656,22 @@ public static IData TryGetDataByUniqueKey(Type interfaceType, DataKeyPropertyCol return data; } + /// + public static IEnumerable TryGetDataVersionsByUniqueKey(Type interfaceType, DataKeyPropertyCollection dataKeyPropertyCollection) + { + if (interfaceType == null) throw new ArgumentNullException("interfaceType"); + if (dataKeyPropertyCollection == null) throw new ArgumentNullException("dataKeyPropertyCollection"); + + LambdaExpression lambdaExpression = GetPredicateExpressionByUniqueKey(interfaceType, dataKeyPropertyCollection); + + MethodInfo methodInfo = GetGetDataWithPredicatMethodInfo(interfaceType); + IQueryable queryable = (IQueryable)methodInfo.Invoke(null, new object[] { lambdaExpression }); + + var datas = queryable.OfType(); + + return datas; + } // Overload /// diff --git a/Composite/Data/DataFacadeImpl.cs b/Composite/Data/DataFacadeImpl.cs index b84dee85ed..f0206692ef 100644 --- a/Composite/Data/DataFacadeImpl.cs +++ b/Composite/Data/DataFacadeImpl.cs @@ -22,7 +22,9 @@ namespace Composite.Data { internal class DataFacadeImpl : IDataFacade { - private static readonly string LogTitle = "DataFacade"; + private static readonly string LogTitle = nameof(DataFacade); + + internal Dictionary GlobalDataInterceptors = new Dictionary(); static readonly Cache _dataBySourceIdCache = new Cache("Data by sourceId", 2000); private static readonly object _storeCreationLock = new object(); @@ -44,37 +46,16 @@ public IQueryable GetData(bool useCaching, IEnumerable providerNam if (DataProviderRegistry.AllInterfaces.Contains(typeof (T))) { - if (useCaching && DataCachingFacade.IsDataAccessCacheEnabled(typeof (T))) + if (useCaching + && providerNames == null + && DataCachingFacade.IsDataAccessCacheEnabled(typeof (T))) { - resultQueryable = DataCachingFacade.GetDataFromCache(); + resultQueryable = DataCachingFacade.GetDataFromCache( + () => BuildQueryFromProviders(null)); } else { - if (providerNames == null) - { - providerNames = DataProviderRegistry.GetDataProviderNamesByInterfaceType(typeof (T)); - } - - List> queryables = new List>(); - foreach (string providerName in providerNames) - { - IQueryable queryable = DataProviderPluginFacade.GetData(providerName); - - queryables.Add(queryable); - } - - bool resultIsCached = queryables.Count == 1 && queryables[0] is ICachedQuery; - - if (resultIsCached) - { - resultQueryable = queryables[0]; - } - else - { - var multipleSourceQueryable = new DataFacadeQueryable(queryables); - - resultQueryable = multipleSourceQueryable; - } + resultQueryable = BuildQueryFromProviders(providerNames); } } else @@ -83,17 +64,14 @@ public IQueryable GetData(bool useCaching, IEnumerable providerNam if (!typeof(T).GetCustomInterfaceAttributes().Any()) { - throw new ArgumentException(string.Format("The given interface type ({0}) is not supported by any data providers", typeof(T))); + throw new ArgumentException($"The given interface type ({typeof (T)}) is not supported by any data providers"); } resultQueryable = new List().AsQueryable(); } - - DataInterceptor dataInterceptor; - this.DataInterceptors.TryGetValue(typeof(T), out dataInterceptor); - if (dataInterceptor != null) + foreach (var dataInterceptor in GetDataInterceptors(typeof(T))) { try { @@ -101,7 +79,6 @@ public IQueryable GetData(bool useCaching, IEnumerable providerNam } catch (Exception ex) { - Log.LogError(LogTitle, "Calling data interceptor failed with the following exception"); Log.LogError(LogTitle, ex); } } @@ -110,13 +87,36 @@ public IQueryable GetData(bool useCaching, IEnumerable providerNam } + private IQueryable BuildQueryFromProviders(IEnumerable providerNames) where T : class, IData + { + if (providerNames == null) + { + providerNames = DataProviderRegistry.GetDataProviderNamesByInterfaceType(typeof(T)); + } + + var queries = new List>(); + foreach (string providerName in providerNames) + { + IQueryable query = DataProviderPluginFacade.GetData(providerName); + + queries.Add(query); + } + bool resultIsCached = queries.Count == 1 && queries[0] is ICachedQuery; + + if (resultIsCached) + { + return queries[0]; + } + + return new DataFacadeQueryable(queries); + } public T GetDataFromDataSourceId(DataSourceId dataSourceId, bool useCaching) where T : class, IData { - if (null == dataSourceId) throw new ArgumentNullException("dataSourceId"); + Verify.ArgumentNotNull(dataSourceId, nameof(dataSourceId)); useCaching = useCaching && DataCachingFacade.IsTypeCacheable(typeof(T)); @@ -145,10 +145,8 @@ public T GetDataFromDataSourceId(DataSourceId dataSourceId, bool useCaching) { resultData = DataWrappingFacade.Wrap(resultData); } - - DataInterceptor dataInterceptor; - this.DataInterceptors.TryGetValue(typeof(T), out dataInterceptor); - if (dataInterceptor != null) + + foreach (var dataInterceptor in GetDataInterceptors(typeof(T))) { try { @@ -156,7 +154,6 @@ public T GetDataFromDataSourceId(DataSourceId dataSourceId, bool useCaching) } catch (Exception ex) { - Log.LogError(LogTitle, "Calling data interceptor failed with the following exception"); Log.LogError(LogTitle, ex); } } @@ -166,6 +163,24 @@ public T GetDataFromDataSourceId(DataSourceId dataSourceId, bool useCaching) } + public IEnumerable GetDataInterceptors(Type dataType) + { + DataInterceptor globalDataInterceptor = GlobalDataInterceptors + .FirstOrDefault(kvp => kvp.Key.IsAssignableFrom(dataType)).Value; + + DataInterceptor threadedDataInterceptor; + this.DataInterceptors.TryGetValue(dataType, out threadedDataInterceptor); + + if (threadedDataInterceptor == null && globalDataInterceptor == null) + { + return Enumerable.Empty(); + } + + var dataInterceptors = new List { threadedDataInterceptor, globalDataInterceptor }; + + return dataInterceptors.Where(d => d != null); + } + public void SetDataInterceptor(DataInterceptor dataInterceptor) where T : class, IData { @@ -173,7 +188,7 @@ public void SetDataInterceptor(DataInterceptor dataInterceptor) where T : cla this.DataInterceptors.Add(typeof(T), dataInterceptor); - Log.LogVerbose(LogTitle, string.Format("Data interception added to the data type '{0}' with interceptor type '{1}'", typeof(T), dataInterceptor.GetType())); + Log.LogVerbose(LogTitle, $"Data interception added to the data type '{typeof (T)}' with interceptor type '{dataInterceptor.GetType()}'"); } @@ -191,12 +206,37 @@ public void ClearDataInterceptor() where T : class, IData { this.DataInterceptors.Remove(typeof(T)); - Log.LogVerbose(LogTitle, string.Format("Data interception cleared for the data type '{0}'", typeof(T))); + Log.LogVerbose(LogTitle, $"Data interception cleared for the data type '{typeof (T)}'"); } } + public void SetGlobalDataInterceptor(DataInterceptor dataInterceptor) where T : class, IData + { + if (GlobalDataInterceptors.ContainsKey(typeof(T))) throw new InvalidOperationException("A data interceptor has already been set"); + + GlobalDataInterceptors.Add(typeof(T), dataInterceptor); + + Log.LogVerbose(LogTitle, + $"Global Data interception added to the data type '{typeof (T)}' with interceptor type '{dataInterceptor.GetType()}'"); + } + + public bool HasGlobalDataInterceptor() where T : class, IData + { + return GlobalDataInterceptors.ContainsKey(typeof(T)); + } + + public void ClearGlobalDataInterceptor() where T : class, IData + { + if (GlobalDataInterceptors.ContainsKey(typeof(T))) + { + GlobalDataInterceptors.Remove(typeof(T)); + + Log.LogVerbose(LogTitle, $"Global Data interception cleared for the data type '{typeof (T)}'"); + } + } + private Dictionary DataInterceptors { get @@ -205,7 +245,7 @@ private Dictionary DataInterceptors var threadData = ThreadDataManager.GetCurrentNotNull(); - Dictionary dataInterceptors = threadData.GetValue(threadDataKey) as Dictionary; + var dataInterceptors = threadData.GetValue(threadDataKey) as Dictionary; if (dataInterceptors == null) { @@ -217,13 +257,13 @@ private Dictionary DataInterceptors } } - + public void Update(IEnumerable dataset, bool suppressEventing, bool performForeignKeyIntegrityCheck, bool performValidation) { Verify.ArgumentNotNull(dataset, "dataset"); - Dictionary>> sortedDataset = dataset.ToDataProviderAndInterfaceTypeSortedDictionary(); + var sortedDataset = dataset.ToDataProviderAndInterfaceTypeSortedDictionary(); if (!suppressEventing) { @@ -420,7 +460,7 @@ public void Delete(IEnumerable dataset, bool suppressEventing, CascadeDele private void Delete(IEnumerable dataset, bool suppressEventing, CascadeDeleteType cascadeDeleteType, bool referencesFromAllScopes, HashSet dataPendingDeletion) where T : class, IData { - Verify.ArgumentNotNull(dataset, "dataset"); + Verify.ArgumentNotNull(dataset, nameof(dataset)); dataset = dataset.Evaluate(); @@ -437,32 +477,50 @@ private void Delete(IEnumerable dataset, bool suppressEventing, CascadeDel { foreach (IData element in dataset) { - Verify.ArgumentCondition(element != null, "dataset", "datas may not contain nulls"); + Verify.ArgumentCondition(element != null, nameof(dataset), "dataset may not contain nulls"); - if (element.IsDataReferred()) - { - Verify.IsTrue(cascadeDeleteType != CascadeDeleteType.Disallow, "One of the given datas is referenced by one or more datas"); + if (!element.IsDataReferred()) continue; + + Type interfaceType = element.DataSourceId.InterfaceType; - element.RemoveOptionalReferences(); + // Not deleting references if the data is versioned and not all of the + // versions of the element are to be deleted + if (element is IVersioned) + { + var key = element.GetUniqueKey(); + var versions = DataFacade.TryGetDataVersionsByUniqueKey(interfaceType, key).ToList(); - IEnumerable referees; - using (new DataScope(element.DataSourceId.DataScopeIdentifier)) + if (versions.Count > 1 + && (dataset.Count() < versions.Count + || !versions.All(v => dataPendingDeletion.Contains(v.DataSourceId)))) { - // For some wierd reason, this line does not work.... /MRJ - // IEnumerable referees = dataset.GetRefereesRecursively(); - referees = element.GetReferees(referencesFromAllScopes).Where(reference => !dataPendingDeletion.Contains(reference.DataSourceId)); + continue; } + } + + Verify.IsTrue(cascadeDeleteType != CascadeDeleteType.Disallow, "One of the given datas is referenced by one or more datas"); + + element.RemoveOptionalReferences(); - foreach (IData referee in referees) + IEnumerable referees; + using (new DataScope(element.DataSourceId.DataScopeIdentifier)) + { + // For some weird reason, this line does not work.... /MRJ + // IEnumerable referees = dataset.GetRefereesRecursively(); + referees = element.GetReferees(referencesFromAllScopes) + .Where(reference => !dataPendingDeletion.Contains(reference.DataSourceId)) + .Evaluate(); + } + + foreach (IData referee in referees) + { + if (!referee.CascadeDeleteAllowed(interfaceType)) { - if (referee.CascadeDeleteAllowed(element.DataSourceId.InterfaceType) == false) - { - throw new InvalidOperationException("One of the given datas is referenced by one or more datas that does not allow cascade delete"); - } + throw new InvalidOperationException("One of the given datas is referenced by one or more datas that does not allow cascade delete"); } - - Delete(referees, suppressEventing, cascadeDeleteType, referencesFromAllScopes); } + + Delete(referees, suppressEventing, cascadeDeleteType, referencesFromAllScopes); } } @@ -483,7 +541,7 @@ private void Delete(IEnumerable dataset, bool suppressEventing, CascadeDel } - if (suppressEventing == false) + if (!suppressEventing) { foreach (IData element in dataset) { diff --git a/Composite/Data/DataIdKeyFacade.cs b/Composite/Data/DataIdKeyFacade.cs index c6961d1a31..586174bda9 100644 --- a/Composite/Data/DataIdKeyFacade.cs +++ b/Composite/Data/DataIdKeyFacade.cs @@ -15,7 +15,7 @@ public static class DataIdKeyFacade /// static DataIdKeyFacade() { - GlobalEventSystemFacade.SubscribeToFlushEvent(OnFlushEvent); + GlobalEventSystemFacade.SubscribeToFlushEvent(args => Flush()); } @@ -23,7 +23,12 @@ static DataIdKeyFacade() // Overload /// public static T GetKeyValue(this DataSourceId dataSourceId, string keyName = null) - { + { + if (keyName == null) + { + keyName = dataSourceId.InterfaceType.GetSingleKeyProperty().Name; + } + return (T)_implementation.GetKeyValue(dataSourceId.DataId, keyName); } @@ -41,7 +46,14 @@ public static T GetKeyValue(IDataId dataId, string keyName = null) // Overload /// public static object GetKeyValue(this DataSourceId dataSourceId, string keyName = null) - { + { + Verify.ArgumentNotNull(dataSourceId, nameof(dataSourceId)); + + if (keyName == null) + { + keyName = dataSourceId.InterfaceType.GetSingleKeyProperty().Name; + } + return _implementation.GetKeyValue(dataSourceId.DataId, keyName); } @@ -77,12 +89,5 @@ private static void Flush() { _implementation.OnFlush(); } - - - - private static void OnFlushEvent(FlushEventArgs args) - { - Flush(); - } } } diff --git a/Composite/Data/DataIdKeyFacadeImpl.cs b/Composite/Data/DataIdKeyFacadeImpl.cs index f3f31bb06b..b990a6409b 100644 --- a/Composite/Data/DataIdKeyFacadeImpl.cs +++ b/Composite/Data/DataIdKeyFacadeImpl.cs @@ -21,10 +21,7 @@ public object GetKeyValue(IDataId dataId, string keyName) } - Func valueFactory = f => - { - return f.GetProperty(keyName); - }; + Func valueFactory = f => f.GetProperty(keyName); PropertyInfo keyPropertyInfo = _keyPropertyInfoCache.GetOrAdd(dataId.GetType(), valueFactory); diff --git a/Composite/Data/DataIdSerializer.cs b/Composite/Data/DataIdSerializer.cs index 2b674deac0..3b363b9056 100644 --- a/Composite/Data/DataIdSerializer.cs +++ b/Composite/Data/DataIdSerializer.cs @@ -10,31 +10,43 @@ namespace Composite.Data { internal static class DataIdSerializer { - public static string Serialize(this IDataId dataId) + public static string Serialize(this IDataId dataId, IEnumerable propertyNames) { if (dataId == null) throw new ArgumentNullException("dataId"); StringBuilder sb = new StringBuilder(); StringConversionServices.SerializeKeyValuePair(sb, "_dataIdType_", TypeManager.SerializeType(dataId.GetType())); - StringConversionServices.SerializeKeyValuePair(sb, "_dataId_", SerializationFacade.Serialize(dataId)); + StringConversionServices.SerializeKeyValuePair(sb, "_dataId_", SerializationFacade.Serialize(dataId, propertyNames)); return sb.ToString(); } + public static IDataId Deserialize(string serializedId, string serializedVersionId) + { + Dictionary dicid = StringConversionServices.ParseKeyValueCollection(serializedId); + if ((dicid.ContainsKey("_dataIdType_") == false) || + (dicid.ContainsKey("_dataId_") == false)) + { + throw new ArgumentException("The serializedId is not a serialized id", nameof(serializedId)); + } - public static IDataId Deserialize(string serializedDataId) - { - Dictionary dic = StringConversionServices.ParseKeyValueCollection(serializedDataId); + Dictionary dicversion = StringConversionServices.ParseKeyValueCollection(serializedVersionId); - if ((dic.ContainsKey("_dataIdType_") == false) || - (dic.ContainsKey("_dataId_") == false)) + if ((dicversion.ContainsKey("_dataIdType_") == false) || + (dicversion.ContainsKey("_dataId_") == false)) { - throw new ArgumentException("The serializedDataId is not a serialized data id", "serializedDataId"); + throw new ArgumentException("The serializedVersionId is not a serialized version id", nameof(serializedVersionId)); + } + + if (dicid["_dataIdType_"] != dicversion["_dataIdType_"]) + { + throw new ArgumentException("Serialized id and version id have diffrent types", nameof(serializedId)); } - string dataIdType = StringConversionServices.DeserializeValueString(dic["_dataIdType_"]); - string serializedDataIdString = StringConversionServices.DeserializeValueString(dic["_dataId_"]); + string dataIdType = StringConversionServices.DeserializeValueString(dicid["_dataIdType_"]); + string serializedIdString = StringConversionServices.DeserializeValueString(dicid["_dataId_"]); + string serializedVersionIdString = StringConversionServices.DeserializeValueString(dicversion["_dataId_"]); Type type = TypeManager.TryGetType(dataIdType); if (type == null) @@ -42,7 +54,7 @@ public static IDataId Deserialize(string serializedDataId) throw new InvalidOperationException(string.Format("The type {0} could not be found", dataIdType)); } - IDataId dataId = SerializationFacade.Deserialize(type, serializedDataIdString); + IDataId dataId = SerializationFacade.Deserialize(type, string.Join("", serializedIdString, serializedVersionIdString)); return dataId; } diff --git a/Composite/Data/DataInterceptor.cs b/Composite/Data/DataInterceptor.cs index eae1e09490..1fcf172830 100644 --- a/Composite/Data/DataInterceptor.cs +++ b/Composite/Data/DataInterceptor.cs @@ -1,30 +1,38 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; namespace Composite.Data { - /// + /// + /// Let you transform queries before data providers. Enable you to augment queries from alternate sources. /// - /// - [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] - public class DataInterceptor + public abstract class DataInterceptor { - /// - public DataInterceptor() + /// + /// Let you transform queries before data providers. Enable you to augment queries from alternate sources. + /// + public virtual IQueryable InterceptGetData(IQueryable dataset) + where T : class, IData { + return dataset; } - - /// - public virtual IQueryable InterceptGetData(IQueryable datas) + /// + /// Let you transform an in-memory result-set. + /// This transformation should behave exactly as the IQueryable equivalent. + /// + public virtual IEnumerable InterceptGetData(IEnumerable dataset) where T : class, IData { - return datas; + return InterceptGetData(dataset.AsQueryable()); } - /// + /// + /// Enable you to intercept queries for a single data item. + /// public virtual T InterceptGetDataFromDataSourceId(T data) where T : class, IData { diff --git a/Composite/Data/DataReference.cs b/Composite/Data/DataReference.cs index f647843346..9267b0eba9 100644 --- a/Composite/Data/DataReference.cs +++ b/Composite/Data/DataReference.cs @@ -57,7 +57,7 @@ public DataReference(object keyValue) { if (keyValue != null) { - Type realKeyType = typeof(T).GetKeyProperties().Single().PropertyType; + Type realKeyType = typeof(T).GetSingleKeyProperty().PropertyType; if (keyValue.GetType() != realKeyType) { _keyValue = ValueTypeConverter.Convert(keyValue, realKeyType); @@ -91,13 +91,7 @@ public DataReference(T data) /// /// The type of the data item. This type inherits from IData. /// - public Type ReferencedType - { - get - { - return typeof(T); - } - } + public Type ReferencedType => typeof(T); /// @@ -118,25 +112,13 @@ public bool IsSet /// /// The key value of the data item being referenced, like the Guid for a page id. /// - public object KeyValue - { - get - { - return _keyValue; - } - } + public object KeyValue => _keyValue; /// /// The data item being referenced. /// - IData IDataReference.Data - { - get - { - return this.Data; - } - } + IData IDataReference.Data => this.Data; /// diff --git a/Composite/Data/DataScope.cs b/Composite/Data/DataScope.cs index 487ed17789..681d915e8e 100644 --- a/Composite/Data/DataScope.cs +++ b/Composite/Data/DataScope.cs @@ -10,9 +10,28 @@ namespace Composite.Data [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public sealed class DataScope : IDisposable { - private readonly bool _dataScopePushed = false; - private readonly bool _cultureInfoPushed = false; + private readonly bool _dataScopePushed; + private readonly bool _cultureInfoPushed; + private bool _dataServicePushed; + private bool _disposed; + private bool _servicesDisabled; + /// + public void AddService(object service) + { + if (!_dataServicePushed) + { + DataServiceScopeManager.PushDataServiceScope(); + _dataServicePushed = true; + } + DataServiceScopeManager.AddService(service); + } + + /// + public void AddDefaultService(object service) + { + DataServiceScopeManager.AddDefaultService(service); + } /// public DataScope(DataScopeIdentifier dataScope) @@ -76,14 +95,33 @@ public DataScope(PublicationScope publicationScope, CultureInfo cultureInfo) /// ~DataScope() { - Dispose(); + Dispose(false); } - - /// public void Dispose() { + Dispose(true); + GC.SuppressFinalize(this); + } + + void Dispose(bool disposing) + { + if (!disposing) + { + return; + } + + if (_disposed) + { + throw new ObjectDisposedException(nameof(DataScope)); + } + + if (_servicesDisabled) + { + EnableServices(); + } + if (_dataScopePushed) { DataScopeManager.PopDataScope(); @@ -93,6 +131,27 @@ public void Dispose() { LocalizationScopeManager.PopLocalizationScope(); } + + if (_dataServicePushed) + { + DataServiceScopeManager.PopDataServiceScope(); + } + + _disposed = true; + } + + internal void DisableServices() + { + DataServiceScopeManager.DisableServices(); + + _servicesDisabled = true; + } + + internal void EnableServices() + { + DataServiceScopeManager.EnableServices(); + + _servicesDisabled = false; } } } diff --git a/Composite/Data/DataScopeIdentifier.cs b/Composite/Data/DataScopeIdentifier.cs index 3798e93511..607fa0fbd5 100644 --- a/Composite/Data/DataScopeIdentifier.cs +++ b/Composite/Data/DataScopeIdentifier.cs @@ -18,10 +18,10 @@ public sealed class DataScopeIdentifier public const string AdministratedName = "administrated"; /// - public static DataScopeIdentifier Public { get { return new DataScopeIdentifier(PublicName); } } + public static DataScopeIdentifier Public { get; } = new DataScopeIdentifier(PublicName); /// - public static DataScopeIdentifier Administrated { get { return new DataScopeIdentifier(AdministratedName); } } + public static DataScopeIdentifier Administrated { get; } = new DataScopeIdentifier(AdministratedName); /// public static DataScopeIdentifier GetDefault() @@ -54,7 +54,7 @@ public string Serialize() /// public static DataScopeIdentifier Deserialize(string serializedData) { - if (serializedData == null) throw new ArgumentNullException("serializedData"); + Verify.ArgumentNotNull(serializedData, nameof(serializedData)); switch (serializedData) { @@ -95,9 +95,7 @@ public static bool IsLegasyDataScope(string name) /// public override bool Equals(object obj) { - if (obj == null) return false; - - return Equals(obj as DataScopeIdentifier); + return obj != null && Equals(obj as DataScopeIdentifier); } diff --git a/Composite/Data/DataScopeServicesFacade.cs b/Composite/Data/DataScopeServicesFacade.cs new file mode 100644 index 0000000000..6111e0bc13 --- /dev/null +++ b/Composite/Data/DataScopeServicesFacade.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Composite.Data +{ + /// + /// Facade for added services to data scope + /// + public static class DataScopeServicesFacade + { + /// + /// Adds a default service to data scope manager. All DataScopes created after this point will include the service you provide. + /// + /// + public static void RegisterDefaultService(object service) + { + DataServiceScopeManager.AddDefaultService(service); + } + } +} diff --git a/Composite/Data/DataServiceScopeManager.cs b/Composite/Data/DataServiceScopeManager.cs new file mode 100644 index 0000000000..c97aa6949b --- /dev/null +++ b/Composite/Data/DataServiceScopeManager.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Remoting.Messaging; +using Composite.Core.Caching; + +namespace Composite.Data +{ + /// + /// + /// + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public static class DataServiceScopeManager + { + internal static void AddService(object service) + { + var serviceStack = DataServiceScopeStack?.Peek(); + Verify.IsNotNull(serviceStack, "The data service stack was not pushed before use"); + + serviceStack.Add(service); + } + + internal static void AddDefaultService(object service) + { + DataServiceDefaultList.Add(service); + } + + internal static void DisableServices() + { + CallContext.SetData(DisableServicesCacheKey, true); + } + + internal static void EnableServices() + { + CallContext.SetData(DisableServicesCacheKey,false); + } + + internal static object GetService(Type t) + { + if (DisableServicesFlag.HasValue && DisableServicesFlag.Value) + return null; + + foreach(var serviceList in DataServiceScopeStack) + { + var match = serviceList?.FindLast(f => f.GetType() == t); + if (match != null) + { + return match; + } + } + + return DataServiceDefaultList.Last(f => f.GetType() == t); + } + + private static readonly List DataServiceDefaultList = new List(); + + private static Stack> DataServiceScopeStack + { + get + { + return CallContext.GetData(ServiceStackCacheKey) as Stack> + ?? RequestLifetimeCache.GetCachedOrNew>>("DataServiceScopeManager:Stack"); + } + } + + private static bool? DisableServicesFlag + { + get + { + return CallContext.GetData(DisableServicesCacheKey) as bool? + ?? RequestLifetimeCache.GetCachedOrNew("DataServiceScopeManagerServiceDisabled:Bool"); + } + } + + /// + /// Move the stack handling scope to a thread local store, enabling simultaneous threads to mutate (their own) scope. This will be in effect untill the thread has completed. + /// + public static void EnterThreadLocal() + { + if (CallContext.GetData(ServiceStackCacheKey) == null) + { + var threadLocalStack = new Stack>(DataServiceScopeStack); + CallContext.SetData(ServiceStackCacheKey, threadLocalStack); + } + + if (CallContext.GetData(DisableServicesCacheKey) == null) + { + var threadLocalStackFlag = DisableServicesFlag; + CallContext.SetData(DisableServicesCacheKey, threadLocalStackFlag); + } + } + + /// + /// Move the stack handling to request scope. + /// + public static void ExitThreadLocal() + { + if (CallContext.GetData(ServiceStackCacheKey) != null) + { + CallContext.SetData(ServiceStackCacheKey, null); + } + + if (CallContext.GetData(DisableServicesCacheKey) != null) + { + CallContext.SetData(DisableServicesCacheKey, null); + } + } + + private const string ServiceStackCacheKey = "DataServiceScopeManager:ThreadLocal"; + private const string DisableServicesCacheKey = "DataServiceScopeManagerDisableServiceFlag:ThreadLocal"; + + + + + internal static void PopDataServiceScope() + { + Verify.That(DataServiceScopeStack.Count > 0, nameof(DataServiceScopeStack) + " underflow"); + + DataServiceScopeStack.Pop(); + } + + internal static void PushDataServiceScope() + { + DataServiceScopeStack.Push(new List()); + } + } +} \ No newline at end of file diff --git a/Composite/Data/DataTypeTypesManager.cs b/Composite/Data/DataTypeTypesManager.cs index 5e41a03ebe..a124aedc1b 100644 --- a/Composite/Data/DataTypeTypesManager.cs +++ b/Composite/Data/DataTypeTypesManager.cs @@ -163,7 +163,10 @@ internal static Dictionary GetDataTypes(IReadOnlyCollection + /// /// Describes a data type in Composite C1 /// [DebuggerDisplay("Type name = {Namespace + '.' + Name}")] public class DataTypeDescriptor { + private const string LogTitle = nameof(DataTypeDescriptor); + private string _name; private Guid _dataTypeId; private string _namespace; @@ -38,6 +40,7 @@ public DataTypeDescriptor() { this.Fields = new DataFieldDescriptorCollection(this); this.KeyPropertyNames = new DataFieldNameCollection(this.Fields, false, false, false); + this.VersionKeyPropertyNames = new DataFieldNameCollection(this.Fields, false, false, false); this.StoreSortOrderFieldNames = new DataFieldNameCollection(this.Fields, true, false, false); this.IsCodeGenerated = false; this.DataScopes = new List(); @@ -122,6 +125,17 @@ public Guid DataTypeId public DataFieldNameCollection KeyPropertyNames { get; set; } + /// + /// Version keys, appear in the physical order but not included in data references. + /// + public DataFieldNameCollection VersionKeyPropertyNames { get; set; } + + + /// + /// Version keys, appear in the physical order but not included in data references. + /// + internal IEnumerable PhysicalKeyPropertyNames => KeyPropertyNames.Concat(VersionKeyPropertyNames); + /// /// Returns the CLT Type for this data type description. /// @@ -156,14 +170,18 @@ public Type GetInterfaceType() public DataFieldDescriptorCollection Fields { get; set; } /// - /// Key fields. Note that the order of the fields is important. + /// Physical key fields. Note that the order of the fields is important. + /// The physical key ensure that storage identity is unique across different versions of data with shared id. /// - internal IEnumerable KeyFields + internal IEnumerable PhysicalKeyFields { get { - return this.KeyPropertyNames.Select(fieldName => this.Fields.Where(field => field.Name == fieldName) - .SingleOrException("Missing a field '{0}'", "Multiple fields with name '{0}'", fieldName)); + Func getField = fieldName => + this.Fields.Where(field => field.Name == fieldName) + .SingleOrException("Missing a field '{0}'", "Multiple fields with name '{0}'", fieldName); + + return PhysicalKeyPropertyNames.Select(getField); } } @@ -269,13 +287,7 @@ public bool HasCustomPhysicalSortOrder /// /// When true data can be localized. /// - public bool Localizeable - { - get - { - return SuperInterfaces.Contains(typeof(ILocalizedControlled)); - } - } + public bool Localizeable => SuperInterfaces.Contains(typeof(ILocalizedControlled)); /// @@ -314,7 +326,7 @@ internal void AddSuperInterface(Type interfaceType, bool addInheritedFields) { foreach (PropertyInfo propertyInfo in interfaceType.GetProperties()) { - if (propertyInfo.Name == "PageId" && interfaceType == typeof (IPageData)) + if (propertyInfo.Name == nameof(IPageData.PageId) && interfaceType == typeof (IPageData)) { continue; } @@ -329,19 +341,7 @@ internal void AddSuperInterface(Type interfaceType, bool addInheritedFields) { if (KeyPropertyNames.Contains(propertyName)) continue; - PropertyInfo property = interfaceType.GetProperty(propertyName); - if (property == null) - { - List superInterfaces = interfaceType.GetInterfacesRecursively(t => typeof(IData).IsAssignableFrom(t) && t != typeof(IData)); - - foreach (Type superInterface in superInterfaces) - { - property = superInterface.GetProperty(propertyName); - if (property != null) break; - } - } - - Verify.IsNotNull(property, "Missing property '{0}' on type '{1}' or one of its interfaces".FormatWith(propertyName, interfaceType)); + PropertyInfo property = ReflectionBasedDescriptorBuilder.FindProperty(interfaceType, propertyName); if (DynamicTypeReflectionFacade.IsKeyField(property)) { @@ -349,7 +349,16 @@ internal void AddSuperInterface(Type interfaceType, bool addInheritedFields) } } - foreach (DataScopeIdentifier dataScopeIdentifier in DynamicTypeReflectionFacade.GetDataScopes(interfaceType)) + foreach (string propertyName in interfaceType.GetVersionKeyPropertyNames()) + { + if (VersionKeyPropertyNames.Contains(propertyName)) continue; + + ReflectionBasedDescriptorBuilder.FindProperty(interfaceType, propertyName); + + this.VersionKeyPropertyNames.Add(propertyName, false); + } + + foreach (var dataScopeIdentifier in DynamicTypeReflectionFacade.GetDataScopes(interfaceType)) { if (!this.DataScopes.Contains(dataScopeIdentifier)) { @@ -357,8 +366,8 @@ internal void AddSuperInterface(Type interfaceType, bool addInheritedFields) } } - - foreach (Type superSuperInterfaceType in interfaceType.GetInterfaces().Where(t => typeof(IData).IsAssignableFrom(t))) + var superInterfaces = interfaceType.GetInterfaces().Where(t => typeof (IData).IsAssignableFrom(t)); + foreach (Type superSuperInterfaceType in superInterfaces) { AddSuperInterface(superSuperInterfaceType, addInheritedFields); } @@ -366,6 +375,8 @@ internal void AddSuperInterface(Type interfaceType, bool addInheritedFields) + + /// /// Removes a super interface /// @@ -384,7 +395,7 @@ public void RemoveSuperInterface(Type interfaceType) foreach (PropertyInfo propertyInfo in interfaceType.GetProperties()) { - DataFieldDescriptor dataFieldDescriptor = ReflectionBasedDescriptorBuilder.BuildFieldDescriptor(propertyInfo, true); + var dataFieldDescriptor = ReflectionBasedDescriptorBuilder.BuildFieldDescriptor(propertyInfo, true); if (this.Fields.Contains(dataFieldDescriptor)) { @@ -399,7 +410,7 @@ public void RemoveSuperInterface(Type interfaceType) } - foreach (DataScopeIdentifier dataScopeIdentifier in DynamicTypeReflectionFacade.GetDataScopes(interfaceType)) + foreach (var dataScopeIdentifier in DynamicTypeReflectionFacade.GetDataScopes(interfaceType)) { if (this.DataScopes.Contains(dataScopeIdentifier)) { @@ -407,10 +418,10 @@ public void RemoveSuperInterface(Type interfaceType) } } - - foreach (Type superSuperInterfaceType in interfaceType.GetInterfaces().Where(t => typeof(IData).IsAssignableFrom(t))) + var superInterfaces = interfaceType.GetInterfaces().Where(t => typeof (IData).IsAssignableFrom(t)); + foreach (Type superInterfaceType in superInterfaces) { - RemoveSuperInterface(superSuperInterfaceType); + RemoveSuperInterface(superInterfaceType); } } @@ -419,14 +430,7 @@ public void RemoveSuperInterface(Type interfaceType) /// /// All interfaces this data type inherit from /// - public IEnumerable SuperInterfaces - { - get - { - return _superInterfaces; - } - } - + public IEnumerable SuperInterfaces => _superInterfaces; /// @@ -467,8 +471,8 @@ public bool IsPageMetaDataType { get { - return - this.DataAssociations.Any(f => f.AssociatedInterfaceType == typeof(IPage) && f.AssociationType == DataAssociationType.Composition); + return this.DataAssociations.Any(f => f.AssociatedInterfaceType == typeof(IPage) + && f.AssociationType == DataAssociationType.Composition); } } @@ -499,17 +503,6 @@ public void Validate() if (this.DataScopes.Count == 0) throw new InvalidOperationException("The DataScopes list containing the list of data scopes this type must support can not be empty. Please provide at least one data scopes."); if (this.DataScopes.Select(f => f.Name).Distinct().Count() != this.DataScopes.Count) throw new InvalidOperationException("The DataScopes list contains redundant data scopes"); - if (this.DataScopes.Any(f => f.Equals(DataScopeIdentifier.PublicName))) - { - foreach (PropertyInfo propertyInfo in typeof(IPublishControlled).GetProperties()) - { - if (!this.Fields.Any(f => f.Name == propertyInfo.Name)) - { - throw new InvalidOperationException(string.Format("DataScope '{0}' require you to implement '{1}' and a field named '{2} is missing", DataScopeIdentifier.Public, typeof(IPublishControlled), propertyInfo.Name)); - } - } - } - this.KeyPropertyNames.ValidateMembers(); this.StoreSortOrderFieldNames.ValidateMembers(); @@ -517,7 +510,7 @@ public void Validate() { if (!this.Fields.Any(f => f.Name == this.LabelFieldName)) { - throw new InvalidOperationException(string.Format("The label field name '{0}' is not an existing field", this.LabelFieldName)); + throw new InvalidOperationException($"The label field name '{this.LabelFieldName}' is not an existing field"); } } @@ -541,8 +534,8 @@ public void Validate() } catch (Exception ex) { - string typeName = (string.IsNullOrEmpty(this.TypeManagerTypeName) ? this.Name : this.TypeManagerTypeName); - throw new InvalidOperationException(string.Format("Failed to validate data type description for '{0}'. {1}", typeName, ex.Message)); + string typeName = string.IsNullOrEmpty(this.TypeManagerTypeName) ? this.Name : this.TypeManagerTypeName; + throw new InvalidOperationException($"Failed to validate data type description for '{typeName}'.", ex); } } @@ -609,7 +602,6 @@ public XElement ToXml() new XAttribute("name", this.Name), new XAttribute("namespace", this.Namespace), this.Title != null ? new XAttribute("title", this.Title) : null, - new XAttribute("hasCustomPhysicalSortOrder", this.HasCustomPhysicalSortOrder), new XAttribute("isCodeGenerated", this.IsCodeGenerated), new XAttribute("cachable", this.Cachable), this.LabelFieldName != null ? new XAttribute("labelFieldName", this.LabelFieldName) : null, @@ -626,6 +618,10 @@ public XElement ToXml() DataScopes.Select(dsi => new XElement("DataScopeIdentifier", new XAttribute("name", dsi)))), new XElement("KeyPropertyNames", KeyPropertyNames.Select(name => new XElement("KeyPropertyName", new XAttribute("name", name)))), + VersionKeyPropertyNames.Any() + ? new XElement("VersionKeyPropertyNames", + VersionKeyPropertyNames.Select(name => new XElement("VersionKeyPropertyName", new XAttribute("name", name)))) + : null, new XElement("SuperInterfaces", SuperInterfaces.Select(su => new XElement("SuperInterface", new XAttribute("type", TypeManager.SerializeType(su))))), new XElement("Fields", Fields.Select(f => f.ToXml())) @@ -660,9 +656,6 @@ internal static DataTypeDescriptor FromXml(XElement element, bool inheritedField string name = element.GetRequiredAttributeValue("name"); string @namespace = element.GetRequiredAttributeValue("namespace"); - // TODO: check why "hasCustomPhysicalSortOrder" is not used - bool hasCustomPhysicalSortOrder = (bool) element.GetRequiredAttribute("hasCustomPhysicalSortOrder"); - bool isCodeGenerated = (bool) element.GetRequiredAttribute("isCodeGenerated"); XAttribute cachableAttribute = element.Attribute("cachable"); XAttribute buildNewHandlerTypeNameAttribute = element.Attribute("buildNewHandlerTypeName"); @@ -710,7 +703,7 @@ internal static DataTypeDescriptor FromXml(XElement element, bool inheritedField string dataScopeName = elm.GetRequiredAttributeValue("name"); if (DataScopeIdentifier.IsLegasyDataScope(dataScopeName)) { - Log.LogWarning("DataTypeDescriptor", "Ignored legacy data scope '{0}' on type '{1}.{2}' while deserializing DataTypeDescriptor. The '{0}' data scope is no longer supported.".FormatWith(dataScopeName, @namespace, name)); + Log.LogWarning(LogTitle, "Ignored legacy data scope '{0}' on type '{1}.{2}' while deserializing DataTypeDescriptor. The '{0}' data scope is no longer supported.".FormatWith(dataScopeName, @namespace, name)); continue; } @@ -725,7 +718,7 @@ internal static DataTypeDescriptor FromXml(XElement element, bool inheritedField if (superInterfaceTypeName.StartsWith("Composite.Data.ProcessControlled.IDeleteControlled")) { - Log.LogWarning("DataTypeDescriptor", string.Format("Ignored legacy super interface '{0}' on type '{1}.{2}' while deserializing DataTypeDescriptor. This super interface is no longer supported.", superInterfaceTypeName, @namespace, name)); + Log.LogWarning(LogTitle, $"Ignored legacy super interface '{superInterfaceTypeName}' on type '{@namespace}.{name}' while deserializing DataTypeDescriptor. This super interface is no longer supported."); continue; } @@ -737,7 +730,7 @@ internal static DataTypeDescriptor FromXml(XElement element, bool inheritedField } catch (Exception ex) { - throw XmlConfigurationExtensionMethods.GetConfigurationException("Failed to load super interface '{0}'".FormatWith(superInterfaceTypeName), ex, elm); + throw XmlConfigurationExtensionMethods.GetConfigurationException($"Failed to load super interface '{superInterfaceTypeName}'", ex, elm); } dataTypeDescriptor.AddSuperInterface(superInterface, !inheritedFieldsIncluded); @@ -818,13 +811,10 @@ public override bool Equals(object obj) /// public bool Equals(DataTypeDescriptor dataTypeDescriptor) { - if (dataTypeDescriptor == null) return false; - - return dataTypeDescriptor.DataTypeId == this.DataTypeId; + return dataTypeDescriptor != null && dataTypeDescriptor.DataTypeId == this.DataTypeId; } - /// public override string ToString() { @@ -868,9 +858,7 @@ public static bool ValidateRuntimeType(this DataTypeDescriptor dataTypeDescripto if (dataTypeDescriptor.IsCodeGenerated) return true; Type dataType = TypeManager.TryGetType(dataTypeDescriptor.TypeManagerTypeName); - if (dataType == null) return false; - - return true; + return dataType != null; } } } diff --git a/Composite/Data/DynamicTypes/DynamicTypeManager.cs b/Composite/Data/DynamicTypes/DynamicTypeManager.cs index af6f4a3f86..0d6fb468e1 100644 --- a/Composite/Data/DynamicTypes/DynamicTypeManager.cs +++ b/Composite/Data/DynamicTypes/DynamicTypeManager.cs @@ -47,9 +47,9 @@ public static DataTypeDescriptor GetDataTypeDescriptor(Type typeToDescript) { DataTypeDescriptor dataTypeDescriptor; - if (TryGetDataTypeDescriptor(typeToDescript.GetImmutableTypeId(), out dataTypeDescriptor) == false) + if (!TryGetDataTypeDescriptor(typeToDescript.GetImmutableTypeId(), out dataTypeDescriptor)) { - dataTypeDescriptor = BuildNewDataTypeDescriptor(typeToDescript); ; + dataTypeDescriptor = BuildNewDataTypeDescriptor(typeToDescript); } return dataTypeDescriptor; @@ -59,10 +59,10 @@ public static DataTypeDescriptor GetDataTypeDescriptor(Type typeToDescript) // Overload /// - public static DataTypeDescriptor GetDataTypeDescriptor(Guid immuteableTypeId) + public static DataTypeDescriptor GetDataTypeDescriptor(Guid immutableTypeId) { DataTypeDescriptor dataTypeDescriptor; - TryGetDataTypeDescriptor(immuteableTypeId, out dataTypeDescriptor); + TryGetDataTypeDescriptor(immutableTypeId, out dataTypeDescriptor); return dataTypeDescriptor; } @@ -79,9 +79,9 @@ public static bool TryGetDataTypeDescriptor(Type interfaceType, out DataTypeDesc /// - public static bool TryGetDataTypeDescriptor(Guid immuteableTypeId, out DataTypeDescriptor dataTypeDescriptor) + public static bool TryGetDataTypeDescriptor(Guid immutableTypeId, out DataTypeDescriptor dataTypeDescriptor) { - return _dynamicTypeManager.TryGetDataTypeDescriptor(immuteableTypeId, out dataTypeDescriptor); + return _dynamicTypeManager.TryGetDataTypeDescriptor(immutableTypeId, out dataTypeDescriptor); } @@ -259,17 +259,11 @@ public static void EnsureCreateStore(Type interfaceType) // Helper public static void EnsureCreateStore(Type interfaceType, string providerName) { - DataTypeDescriptor dataTypeDescriptor; - if (!TryGetDataTypeDescriptor(interfaceType, out dataTypeDescriptor)) - { - dataTypeDescriptor = BuildNewDataTypeDescriptor(interfaceType); - } - IEnumerable dynamicProviderNames; if (providerName == null) { - // Checking if any of exising dynamic data providers already has a store for the specified interface type + // Checking if any of existing dynamic data providers already has a store for the specified interface type providerName = DataProviderRegistry.DefaultDynamicTypeDataProviderName; dynamicProviderNames = DataProviderRegistry.DynamicDataProviderNames; } @@ -286,6 +280,8 @@ public static void EnsureCreateStore(Type interfaceType, string providerName) return; } + var dataTypeDescriptor = BuildNewDataTypeDescriptor(interfaceType); + CreateStore(providerName, dataTypeDescriptor, true); CodeGenerationManager.GenerateCompositeGeneratedAssembly(true); } diff --git a/Composite/Data/DynamicTypes/Foundation/ReflectionBasedDataTypeDescriptorBuilder.cs b/Composite/Data/DynamicTypes/Foundation/ReflectionBasedDataTypeDescriptorBuilder.cs index 7d48512751..0140148515 100644 --- a/Composite/Data/DynamicTypes/Foundation/ReflectionBasedDataTypeDescriptorBuilder.cs +++ b/Composite/Data/DynamicTypes/Foundation/ReflectionBasedDataTypeDescriptorBuilder.cs @@ -50,7 +50,7 @@ public static DataTypeDescriptor Build(Type type) { foreach (PropertyInfo propertyInfo in superInterfaceType.GetProperties()) { - if (propertyInfo.Name == "PageId" && propertyInfo.DeclaringType == typeof(IPageData)) + if (propertyInfo.Name == nameof(IPageData.PageId) && propertyInfo.DeclaringType == typeof(IPageData)) { continue; } @@ -61,7 +61,7 @@ public static DataTypeDescriptor Build(Type type) } } - ValidateAndAddKeyProperties(typeDescriptor.KeyPropertyNames, type, superInterfaces); + ValidateAndAddKeyProperties(typeDescriptor.KeyPropertyNames, typeDescriptor.VersionKeyPropertyNames, type); string[] storeSortOrder = DynamicTypeReflectionFacade.GetSortOrder(type); if (storeSortOrder != null) @@ -74,7 +74,7 @@ public static DataTypeDescriptor Build(Type type) CheckSortOrder(typeDescriptor); - foreach (DataScopeIdentifier dataScopeIdentifier in DynamicTypeReflectionFacade.GetDataScopes(type)) + foreach (var dataScopeIdentifier in DynamicTypeReflectionFacade.GetDataScopes(type)) { if (!typeDescriptor.DataScopes.Contains(dataScopeIdentifier)) { @@ -86,7 +86,8 @@ public static DataTypeDescriptor Build(Type type) { if (typeDescriptor.Fields[keyPropertyName] == null) { - throw new InvalidOperationException(string.Format("The type '{0}' has a non existing key property specified by the attribute '{1}'", type, typeof(KeyPropertyNameAttribute))); + throw new InvalidOperationException( + $"The type '{type}' has a non existing key property specified by the attribute '{typeof (KeyPropertyNameAttribute)}'"); } } @@ -97,7 +98,7 @@ public static DataTypeDescriptor Build(Type type) { if (typeDescriptor.Fields[field.Item1] == null) { - throw new InvalidOperationException(string.Format("Index field '{0}' is not defined", field.Item1)); + throw new InvalidOperationException($"Index field '{field.Item1}' is not defined"); } } @@ -111,30 +112,49 @@ public static DataTypeDescriptor Build(Type type) return typeDescriptor; } - static void ValidateAndAddKeyProperties(DataFieldNameCollection keyProperties, Type interfaceType, IList superInterfacesType) + static void ValidateAndAddKeyProperties( + DataFieldNameCollection keyProperties, + DataFieldNameCollection versionKeyProperties, + Type interfaceType) { - foreach (string propertyName in DataAttributeFacade.GetKeyPropertyNames(interfaceType)) + foreach (string propertyName in interfaceType.GetKeyPropertyNames()) { - PropertyInfo property = interfaceType.GetProperty(propertyName); - if (property == null) - { - foreach (Type superInterface in superInterfacesType) - { - property = superInterface.GetProperty(propertyName); - if(property != null) break; - } - } - - Verify.IsNotNull(property, "Missing property '{0}' on type '{1}' or one of its interfaces".FormatWith(propertyName, interfaceType)); + PropertyInfo property = FindProperty(interfaceType, propertyName); if (DynamicTypeReflectionFacade.IsKeyField(property)) { keyProperties.Add(propertyName, false); } } + + foreach (string propertyName in interfaceType.GetVersionKeyPropertyNames()) + { + FindProperty(interfaceType, propertyName); + + versionKeyProperties.Add(propertyName, false); + } } + internal static PropertyInfo FindProperty(Type interfaceType, string propertyName) + { + PropertyInfo property = interfaceType.GetProperty(propertyName); + if (property == null) + { + List superInterfaces = interfaceType.GetInterfacesRecursively(t => typeof(IData).IsAssignableFrom(t) && t != typeof(IData)); + + foreach (Type superInterface in superInterfaces) + { + property = superInterface.GetProperty(propertyName); + if (property != null) break; + } + } + + Verify.IsNotNull(property, $"Missing property '{propertyName}' on type '{interfaceType}' or one of its interfaces"); + + return property; + } + internal static DataFieldDescriptor BuildFieldDescriptor(PropertyInfo propertyInfo, bool inherited) { string fieldName = propertyInfo.Name; @@ -150,7 +170,9 @@ internal static DataFieldDescriptor BuildFieldDescriptor(PropertyInfo propertyIn IsNullable = DynamicTypeReflectionFacade.IsNullable(propertyInfo), ForeignKeyReferenceTypeName = DynamicTypeReflectionFacade.ForeignKeyReferenceTypeName(propertyInfo), GroupByPriority = DynamicTypeReflectionFacade.GetGroupByPriority(propertyInfo), - TreeOrderingProfile = DynamicTypeReflectionFacade.GetTreeOrderingProfile(propertyInfo) + TreeOrderingProfile = DynamicTypeReflectionFacade.GetTreeOrderingProfile(propertyInfo), + NewInstanceDefaultFieldValue = DynamicTypeReflectionFacade.NewInstanceDefaultFieldValue(propertyInfo), + IsReadOnly = !propertyInfo.CanWrite }; var formRenderingProfile = DynamicTypeReflectionFacade.GetFormRenderingProfile(propertyInfo); @@ -173,18 +195,8 @@ internal static DataFieldDescriptor BuildFieldDescriptor(PropertyInfo propertyIn //} int position; - if (DynamicTypeReflectionFacade.TryGetFieldPosition(propertyInfo, out position)) - { - fieldDescriptor.Position = position; - } - else - { - fieldDescriptor.Position = 1000; - } - - fieldDescriptor.NewInstanceDefaultFieldValue = DynamicTypeReflectionFacade.NewInstanceDefaultFieldValue(propertyInfo); - - fieldDescriptor.IsReadOnly = !propertyInfo.CanWrite; + fieldDescriptor.Position = DynamicTypeReflectionFacade.TryGetFieldPosition(propertyInfo, out position) + ? position : 1000; return fieldDescriptor; } @@ -225,7 +237,7 @@ private static void CheckSortOrder(DataTypeDescriptor typeDescriptor) if (typeDescriptor.StoreSortOrderFieldNames.Count != typeDescriptor.Fields.Count) { - throw new InvalidOperationException(string.Format("The store sort order attribute should list all the fields of the interface")); + throw new InvalidOperationException("The store sort order attribute should list all the fields of the interface"); } } } diff --git a/Composite/Data/ForeignKeyAttribute.cs b/Composite/Data/ForeignKeyAttribute.cs index 2572887b50..be0799f112 100644 --- a/Composite/Data/ForeignKeyAttribute.cs +++ b/Composite/Data/ForeignKeyAttribute.cs @@ -1,7 +1,5 @@ using System; -using System.Linq; using Composite.Core.Types; -using Composite.Data.DynamicTypes; namespace Composite.Data @@ -112,11 +110,7 @@ public bool NullableString /// - public bool IsNullReferenceValueSet - { - get { return _isNullReferenceValueSet; } - } - + public bool IsNullReferenceValueSet => _isNullReferenceValueSet; /// @@ -181,11 +175,14 @@ public string KeyPropertyName { get { - lock (_lock) + if (_keyPropertyName == null) { - if (_keyPropertyName == null) + lock (_lock) { - _keyPropertyName = DynamicTypeManager.GetDataTypeDescriptor(this.InterfaceType).KeyPropertyNames.Single(); + if (_keyPropertyName == null) + { + _keyPropertyName = InterfaceType.GetSingleKeyProperty().Name; + } } } diff --git a/Composite/Data/Foundation/CodeGeneration/DataWrapperGenerator.cs b/Composite/Data/Foundation/CodeGeneration/DataWrapperGenerator.cs index 290b69c1bb..d8b123124d 100644 --- a/Composite/Data/Foundation/CodeGeneration/DataWrapperGenerator.cs +++ b/Composite/Data/Foundation/CodeGeneration/DataWrapperGenerator.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using Composite.Core.Types; using Composite.Data.DynamicTypes; @@ -9,32 +11,63 @@ namespace Composite.Data.Foundation.CodeGeneration { /// /// This class handles data wrapper types and cashing. - /// It will through genereated + /// It will through generated /// data wrapper class types if needed. /// internal static class DataWrapperTypeManager { - private static readonly object _lock = new object(); + private static readonly object _compilationLock = new object(); + private static readonly ConcurrentDictionary _dataWrappersCache + = new ConcurrentDictionary(); - public static Type GetDataWrapperType(Type interfaceType) + delegate T ObjectActivator(T param); + + private static readonly ConcurrentDictionary _dataWrappersActivatorCache + = new ConcurrentDictionary(); + + public static Func GetWrapperConstructor() { - Type wrapperType = TryGetWrapperType(interfaceType.FullName); - if (wrapperType != null) return wrapperType; + return (Func < T, T >)_dataWrappersActivatorCache.GetOrAdd(typeof (T), type => + { + var wrapperType = GetDataWrapperType(typeof (T)); + + var param = Expression.Parameter(typeof (T)); + + var constructor = wrapperType.GetConstructors().Single(); + var ctrExpression = Expression.New(constructor, param); + + var lambda = Expression.Lambda(typeof (ObjectActivator), ctrExpression, param); + var activator = (ObjectActivator) lambda.Compile(); + + Func func = obj => activator(obj); - lock (_lock) + return func; + }); + } + + + public static Type GetDataWrapperType(Type interfaceType) + { + return _dataWrappersCache.GetOrAdd(interfaceType, type => { - wrapperType = TryGetWrapperType(interfaceType.FullName); + Type wrapperType = TryGetWrapperType(type.FullName); if (wrapperType != null) return wrapperType; - var codeGenerationBuilder = new CodeGenerationBuilder("DataWrapper:" + interfaceType.FullName); + lock (_compilationLock) + { + wrapperType = TryGetWrapperType(type.FullName); + if (wrapperType != null) return wrapperType; - DataWrapperCodeGenerator.AddDataWrapperClassCode(codeGenerationBuilder, interfaceType); + var codeGenerationBuilder = new CodeGenerationBuilder("DataWrapper:" + type.FullName); - IEnumerable types = CodeGenerationManager.CompileRuntimeTempTypes(codeGenerationBuilder); + DataWrapperCodeGenerator.AddDataWrapperClassCode(codeGenerationBuilder, type); - return types.Single(); - } + IEnumerable types = CodeGenerationManager.CompileRuntimeTempTypes(codeGenerationBuilder); + + return types.Single(); + } + }); } @@ -44,7 +77,7 @@ public static Type GetDataWrapperType(DataTypeDescriptor dataTypeDescriptor) Type wrapperType = TryGetWrapperType(dataTypeDescriptor.GetFullInterfaceName()); if (wrapperType != null) return wrapperType; - lock (_lock) + lock (_compilationLock) { wrapperType = TryGetWrapperType(dataTypeDescriptor.GetFullInterfaceName()); if (wrapperType != null) return wrapperType; diff --git a/Composite/Data/Foundation/DataExpressionBuilder.cs b/Composite/Data/Foundation/DataExpressionBuilder.cs index dc49916b09..0a861aa5c2 100644 --- a/Composite/Data/Foundation/DataExpressionBuilder.cs +++ b/Composite/Data/Foundation/DataExpressionBuilder.cs @@ -88,7 +88,7 @@ public static Delegate GetWherePredicateDelegate(IData data, bool ignoreVersioni private static LambdaExpression GetWhereLambdaExpression(IData data, bool ignoreVersioning) { - var propertyInfoes = data.DataSourceId.InterfaceType.GetKeyProperties(); + var propertyInfoes = data.DataSourceId.InterfaceType.GetPhysicalKeyProperties(); if (propertyInfoes.Count == 0) { diff --git a/Composite/Data/Foundation/DataReferenceRegistry.cs b/Composite/Data/Foundation/DataReferenceRegistry.cs index 8786c10f95..a4b2f65139 100644 --- a/Composite/Data/Foundation/DataReferenceRegistry.cs +++ b/Composite/Data/Foundation/DataReferenceRegistry.cs @@ -95,8 +95,10 @@ private static void AddNewType(Type interfaceType) foreach (ForeignPropertyInfo foreignKeyPropertyInfo in foreignKeyProperties) { - if (foreignKeyPropertyInfo.SourcePropertyInfo.CanRead == false) throw new InvalidOperationException(string.Format("The property '{0}' shoud have a getter", foreignKeyPropertyInfo.SourcePropertyInfo)); - if (foreignKeyPropertyInfo.TargetType.IsNotReferenceable()) throw new InvalidOperationException(string.Format("The referenced type '{0}' is marked NotReferenceable and can not be referenced by the interfaceType '{1}'", foreignKeyPropertyInfo.TargetType, interfaceType)); + if (!foreignKeyPropertyInfo.SourcePropertyInfo.CanRead) throw new InvalidOperationException( + $"The property '{foreignKeyPropertyInfo.SourcePropertyInfo}' shoud have a getter"); + if (foreignKeyPropertyInfo.TargetType.IsNotReferenceable()) throw new InvalidOperationException( + $"The referenced type '{foreignKeyPropertyInfo.TargetType}' is marked NotReferenceable and can not be referenced by the interfaceType '{interfaceType}'"); PropertyInfo propertyInfo = foreignKeyPropertyInfo.TargetType.GetDataPropertyRecursively(foreignKeyPropertyInfo.TargetKeyPropertyName); @@ -112,7 +114,8 @@ private static void AddNewType(Type interfaceType) sourcePropertyType = sourcePropertyType.GetGenericArguments()[0]; } - if (propertyInfo.PropertyType != sourcePropertyType) throw new InvalidOperationException(string.Format("Type mismatch '{0}' and '{1}' does not match from the two properties '{2}' and '{3}'", propertyInfo.PropertyType, foreignKeyPropertyInfo.SourcePropertyInfo.PropertyType, propertyInfo, foreignKeyPropertyInfo.SourcePropertyInfo)); + if (propertyInfo.PropertyType != sourcePropertyType) throw new InvalidOperationException( + $"Type mismatch '{propertyInfo.PropertyType}' and '{foreignKeyPropertyInfo.SourcePropertyInfo.PropertyType}' does not match from the two properties '{propertyInfo}' and '{foreignKeyPropertyInfo.SourcePropertyInfo}'"); foreignKeyPropertyInfo.TargetKeyPropertyInfo = propertyInfo; } @@ -142,7 +145,7 @@ private static void AddNewType(Type interfaceType) if (!DataProviderRegistry.AllInterfaces.Contains(foreignKeyPropertyInfo.TargetType)) { - Log.LogCritical(LogTitle, string.Format("The one type '{0}' is referring the non supported data type '{1}'", interfaceType, foreignKeyPropertyInfo.TargetType)); + Log.LogCritical(LogTitle, $"The one type '{interfaceType}' is referring the non supported data type '{foreignKeyPropertyInfo.TargetType}'"); } } } diff --git a/Composite/Data/Foundation/EmptyDataClassTypeManager.cs b/Composite/Data/Foundation/EmptyDataClassTypeManager.cs index 6f06345683..d1fa8a388f 100644 --- a/Composite/Data/Foundation/EmptyDataClassTypeManager.cs +++ b/Composite/Data/Foundation/EmptyDataClassTypeManager.cs @@ -41,14 +41,9 @@ static EmptyDataClassTypeManager() /// The empty class type for the given data interface type. public static Type GetEmptyDataClassType(Type interfaceType, bool forceReCompilation = false) { - if (!DataTypeTypesManager.IsAllowedDataTypeAssembly(interfaceType)) - { - string message = string.Format("The data interface '{0}' is not located in an assembly in the website Bin folder. Please move it to that location", interfaceType); - Log.LogError("EmptyDataClassTypeManager", message); - throw new InvalidOperationException(message); - } + VerifyAssemblyLocation(interfaceType); - DataTypeDescriptor dataTypeDescriptor = DataMetaDataFacade.GetDataTypeDescriptor(interfaceType.GetImmutableTypeId(), true); + var dataTypeDescriptor = DataMetaDataFacade.GetDataTypeDescriptor(interfaceType.GetImmutableTypeId(), true); return GetEmptyDataClassType(dataTypeDescriptor, forceReCompilation); } @@ -124,22 +119,26 @@ private static Type GetEmptyClassFromBuildNewHandler(DataTypeDescriptor dataType Type dataType = DataTypeTypesManager.GetDataType(dataTypeDescriptor); - if (!DataTypeTypesManager.IsAllowedDataTypeAssembly(dataType)) - { - string message = string.Format("The data interface '{0}' is not located in an assembly in the website Bin folder. Please move it to that location", dataType); - Log.LogError("EmptyDataClassTypeManager", message); - throw new InvalidOperationException(message); - } + VerifyAssemblyLocation(dataType); return buildNewHandler.GetTypeToBuild(dataType); } - + private static void VerifyAssemblyLocation(Type interfaceType) + { + if (!DataTypeTypesManager.IsAllowedDataTypeAssembly(interfaceType)) + { + string message = $"The data interface '{interfaceType}' is not located in an assembly in the website Bin folder. Please move it to that location"; + Log.LogError(nameof(EmptyDataClassTypeManager), message); + throw new InvalidOperationException(message); + } + } + internal static Type CreateEmptyDataClassType(DataTypeDescriptor dataTypeDescriptor, Type baseClassType = null, CodeAttributeDeclaration codeAttributeDeclaration = null) { - CodeGenerationBuilder codeGenerationBuilder = new CodeGenerationBuilder("EmptyDataClass: " + dataTypeDescriptor.Name); + var codeGenerationBuilder = new CodeGenerationBuilder("EmptyDataClass: " + dataTypeDescriptor.Name); EmptyDataClassCodeGenerator.AddAssemblyReferences(codeGenerationBuilder, dataTypeDescriptor); EmptyDataClassCodeGenerator.AddEmptyDataClassTypeCode(codeGenerationBuilder, dataTypeDescriptor, baseClassType, codeAttributeDeclaration); diff --git a/Composite/Data/IDataExtensions.cs b/Composite/Data/IDataExtensions.cs index 9c704e53da..7344f8e601 100644 --- a/Composite/Data/IDataExtensions.cs +++ b/Composite/Data/IDataExtensions.cs @@ -187,7 +187,7 @@ public static object GetUniqueKey(this IData data) { Verify.ArgumentNotNull(data, "data"); - return data.DataSourceId.InterfaceType.GetKeyProperties().Single().GetValue(data, null); + return data.DataSourceId.InterfaceType.GetSingleKeyProperty().GetValue(data, null); } diff --git a/Composite/Data/IDataFacade.cs b/Composite/Data/IDataFacade.cs index 1b4c5891be..6e84ac56ff 100644 --- a/Composite/Data/IDataFacade.cs +++ b/Composite/Data/IDataFacade.cs @@ -13,6 +13,7 @@ internal interface IDataFacade void SetDataInterceptor(DataInterceptor dataInterceptor) where T : class, IData; bool HasDataInterceptor() where T : class, IData; void ClearDataInterceptor() where T : class, IData; + IEnumerable GetDataInterceptors(Type interfaceType); IQueryable GetData(bool useCaching, IEnumerable providerNames) where T : class, IData; @@ -53,5 +54,9 @@ internal interface IDataFacade /// /// bool ValidatePath(TFile file, string providerName, out string errorMessage) where TFile : IFile; + + void SetGlobalDataInterceptor(DataInterceptor dataInterceptor) where T : class, IData; + bool HasGlobalDataInterceptor() where T : class, IData; + void ClearGlobalDataInterceptor() where T : class, IData; } } diff --git a/Composite/Data/IPageMetaData.cs b/Composite/Data/IPageMetaData.cs index 0ddd9407ea..c53eeba43b 100644 --- a/Composite/Data/IPageMetaData.cs +++ b/Composite/Data/IPageMetaData.cs @@ -1,5 +1,6 @@ using Composite.Data.ProcessControlled.ProcessControllers.GenericPublishProcessController; using Composite.Data.ProcessControlled; +using Composite.Data.Types; namespace Composite.Data @@ -12,7 +13,7 @@ namespace Composite.Data [DataScope(DataScopeIdentifier.AdministratedName)] [PublishProcessControllerType(typeof(GenericPublishProcessController))] [DataAssociationAttribute(typeof(Composite.Data.Types.IPage), "PageId", DataAssociationType.Composition)] - public interface IPageMetaData : IPageData, IPublishControlled + public interface IPageMetaData : IPageData, IPublishControlled, IVersioned { /// [StoreFieldType(PhysicalStoreFieldType.String, 128)] diff --git a/Composite/Data/KeyPropertyNameAttribute.cs b/Composite/Data/KeyPropertyNameAttribute.cs index aa81d3a6ec..3e01be2342 100644 --- a/Composite/Data/KeyPropertyNameAttribute.cs +++ b/Composite/Data/KeyPropertyNameAttribute.cs @@ -1,5 +1,4 @@ using System; -using System.Data.SqlClient; namespace Composite.Data { diff --git a/Composite/Data/PageManager.cs b/Composite/Data/PageManager.cs index 6449e60816..b3dcec1d3f 100644 --- a/Composite/Data/PageManager.cs +++ b/Composite/Data/PageManager.cs @@ -8,7 +8,6 @@ using Composite.Data.Foundation; using Composite.Core.Extensions; using Composite.Core.Types; -using NullableGuid = Composite.Core.Types.ExtendedNullable; using Composite.Data.Types; namespace Composite.Data @@ -42,7 +41,7 @@ public PageStructureRecord(IPageStructure ps) private static readonly int ChildrenCacheSize = 2000; private static readonly int PagePlaceholderCacheSize = 500; - private static readonly Cache> _pageCache = new Cache>("Pages", PageCacheSize); + private static readonly Cache> _pageCache = new Cache>("Pages", PageCacheSize); private static readonly Cache> _placeholderCache = new Cache>("Page placeholders", PagePlaceholderCacheSize); private static readonly Cache> _pageStructureCache = new Cache>("Page structure", PageStructureCacheSize); private static readonly Cache> _childrenCache = new Cache>("Child pages", ChildrenCacheSize); @@ -50,7 +49,7 @@ public PageStructureRecord(IPageStructure ps) private static readonly object _preloadingSyncRoot = new object(); private static bool _pageStructurePreloaded; private static readonly HashSet _preloadedPageDataScopes = new HashSet(); - + static PageManager() { @@ -59,7 +58,6 @@ static PageManager() #region Public methods - /// public static IPage GetPageById(Guid id) { @@ -70,24 +68,37 @@ public static IPage GetPageById(Guid id) /// public static IPage GetPageById(Guid id, bool readonlyValue) { - IPage result; - - string cacheKey = GetCacheKey(id); - var cachedValue = _pageCache.Get(cacheKey); + var versions = GetAllPageVersions(id); + if (versions == null || versions.Count == 0) + { + return null; + } - if (cachedValue != null) + IEnumerable filteredVersions = versions; + foreach (var dataInterceptor in DataFacade.GetDataInterceptors(typeof(IPage))) { - result = cachedValue.Value; + filteredVersions = dataInterceptor.InterceptGetData(filteredVersions); } - else + + var result = filteredVersions.FirstOrDefault(); + if (result == null) { - result = (from page in DataFacade.GetData(false) - where page.Id == id - select page).FirstOrDefault(); + return null; + } - _pageCache.Add(cacheKey, new ExtendedNullable { Value = result }); + return readonlyValue ? result : CreateWrapper(result); + } + + /// + public static IPage GetPageById(Guid id, Guid versionId, bool readonlyValue = false) + { + var versions = GetAllPageVersions(id); + if (versions == null || versions.Count == 0) + { + return null; } + var result = versions.FirstOrDefault(v => v.VersionId == versionId); if (result == null) { return null; @@ -96,6 +107,28 @@ public static IPage GetPageById(Guid id, bool readonlyValue) return readonlyValue ? result : CreateWrapper(result); } + private static IReadOnlyCollection GetAllPageVersions(Guid pageId) + { + string cacheKey = GetCacheKey(pageId, Guid.Empty); + IReadOnlyCollection allPageVersions = _pageCache.Get(cacheKey); + + if (allPageVersions == null) + { + using (var conn = new DataConnection()) + { + conn.DisableServices(); + + allPageVersions = new ReadOnlyCollection( + conn.Get().Where(p => p.Id == pageId).ToList() + ); + } + + _pageCache.Add(cacheKey, allPageVersions); + } + + return allPageVersions; + } + /// [Obsolete("Use GetParentId(..)", true)] @@ -109,7 +142,7 @@ public static Guid GetParentID(Guid pageId) public static Guid GetParentId(Guid pageId) { PageStructureRecord pageStructure = GetPageStructureRecord(pageId); - return pageStructure != null ? pageStructure.ParentId : Guid.Empty; + return pageStructure?.ParentId ?? Guid.Empty; } @@ -117,7 +150,7 @@ public static Guid GetParentId(Guid pageId) public static int GetLocalOrdering(Guid pageId) { PageStructureRecord pageStructure = GetPageStructureRecord(pageId); - return pageStructure != null ? pageStructure.LocalOrdering : 0; + return pageStructure?.LocalOrdering ?? 0; } @@ -151,18 +184,29 @@ orderby ps.LocalOrdering } - /// + [Obsolete("Use an overload also accepting a version id")] public static ReadOnlyCollection GetPlaceholderContent(Guid pageId) { - string cacheKey = GetCacheKey(pageId); + IPage page = GetPageById(pageId); + + return GetPlaceholderContent(pageId, page.VersionId); + } + + + /// + public static ReadOnlyCollection GetPlaceholderContent(Guid pageId, Guid versionId) + { + string cacheKey = GetCacheKey(pageId, versionId); var cachedValue = _placeholderCache.Get(cacheKey); if (cachedValue != null) { return cachedValue; } - var list = DataFacade.GetData(f => f.PageId == pageId).ToList(); + var list = DataFacade.GetData() + .Where(f => f.PageId == pageId + && f.VersionId == versionId).ToList(); var readonlyList = new ReadOnlyCollection(list); @@ -183,12 +227,21 @@ internal static void PreloadPageCaching() { if (!_preloadedPageDataScopes.Contains(key)) { - var pages = DataFacade.GetData().Evaluate(); - - foreach (var page in pages) + using (var conn = new DataConnection()) { - string pageKey = GetCacheKey(page.Id, page.DataSourceId); - _pageCache.Add(pageKey, new ExtendedNullable { Value = page }); + conn.DisableServices(); + + var pages = DataFacade.GetData().GroupBy(p => p.Id).Evaluate(); + if (pages.Count > 0) + { + var dataSourceId = pages.First().First().DataSourceId; + + foreach (var pageVersionsGroup in pages) + { + string pageKey = GetCacheKey(pageVersionsGroup.Key, dataSourceId); + _pageCache.Add(pageKey, new ReadOnlyCollection(pageVersionsGroup.ToList())); + } + } } _preloadedPageDataScopes.Add(key); @@ -256,7 +309,7 @@ private static PageStructureRecord GetPageStructureRecord(Guid pageId) return result; } - private static string GetCacheKey(Guid id) + private static string GetCacheKey(Guid id, Guid versionId) { var cultureInfo = LocalizationScopeManager.MapByType(typeof (T)); Verify.IsNotNull(cultureInfo, "Localization culture is not set"); @@ -264,14 +317,20 @@ private static string GetCacheKey(Guid id) var dataScope = DataScopeManager.MapByType(typeof (T)); Verify.IsNotNull(dataScope, "Publication scope is not set"); - return id + dataScope.Name + cultureInfo; + return id + dataScope.Name + cultureInfo + (versionId != Guid.Empty ? versionId.ToString() : ""); } private static string GetCacheKey(Guid id, DataSourceId dataSourceId) + { + return GetCacheKey(id, Guid.Empty, dataSourceId); + } + + private static string GetCacheKey(Guid id, Guid versionId, DataSourceId dataSourceId) { string localizationInfo = dataSourceId.LocaleScope.ToString(); string dataScope = dataSourceId.DataScopeIdentifier.Name; - return id + dataScope + localizationInfo; + string versionIdStr = versionId != Guid.Empty ? versionId.ToString() : ""; + return id + dataScope + localizationInfo + versionIdStr; } private static void OnPageStoreChanged(object sender, StoreEventArgs storeEventArgs) @@ -315,7 +374,7 @@ private static void OnPagePlaceholderChanged(object sender, DataEventArgs args) return; } - _placeholderCache.Remove(GetCacheKey(placeHolder.PageId, placeHolder.DataSourceId)); + _placeholderCache.Remove(GetCacheKey(placeHolder.PageId, placeHolder.VersionId, placeHolder.DataSourceId)); } @@ -364,6 +423,6 @@ private static void SubscribeToEvents() DataEventSystemFacade.SubscribeToStoreChanged(OnPageStructureStoreChanged, true); } - #endregion Private + #endregion Private } } diff --git a/Composite/Data/PageMetaDataFacade.cs b/Composite/Data/PageMetaDataFacade.cs index 86f33feee3..3d5cbaee33 100644 --- a/Composite/Data/PageMetaDataFacade.cs +++ b/Composite/Data/PageMetaDataFacade.cs @@ -28,9 +28,10 @@ public static class PageMetaDataFacade { private static readonly Guid DefaultCompositionContainerId = new Guid("eb210a75-be25-401f-b0d4-b3787bce36fa"); - internal static readonly string MetaDataType_IdFieldName = "Id"; - internal static readonly string MetaDataType_PageReferenceFieldName = "PageId"; - internal static readonly string MetaDataType_MetaDataDefinitionFieldName = "FieldName"; + internal static readonly string MetaDataType_IdFieldName = nameof(IPageMetaData.Id); + internal static readonly string MetaDataType_PageReferenceFieldName = nameof(IPageMetaData.PageId); + internal static readonly string MetaDataType_PageReferenceFieldVersionName = nameof(IPageMetaData.VersionId); + internal static readonly string MetaDataType_MetaDataDefinitionFieldName = nameof(IPageMetaData.FieldName); /// /// Returns all possible meta data types. This is NOT types that only have been defined on any pages or page type @@ -337,18 +338,19 @@ public static IData GetMetaData(this IPage page, string definitionName, Guid met /// public static IData GetMetaData(this IPage page, string definitionName, Type metaDataType) { - return GetMetaData(page.Id, definitionName, metaDataType); + return GetMetaData(page.Id,page.VersionId, definitionName, metaDataType); } /// - public static IData GetMetaData(Guid pageId, string definitionName, Type metaDataType) + public static IData GetMetaData(Guid pageId, Guid pageVersionId, string definitionName, Type metaDataType) { //TODO: Consider caching here ParameterExpression parameterExpression = Expression.Parameter(metaDataType); LambdaExpression lambdaExpression = Expression.Lambda( + Expression.And( Expression.And( Expression.Equal( Expression.Property( @@ -370,6 +372,17 @@ public static IData GetMetaData(Guid pageId, string definitionName, Type metaDat typeof(Guid) ) ) + ), + Expression.Equal( + Expression.Property( + parameterExpression, + GetDefinitionPageReferencePropertyVersionInfo(metaDataType) + ), + Expression.Constant( + pageVersionId, + typeof(Guid) + ) + ) ), parameterExpression ); @@ -508,17 +521,15 @@ public static bool IsDefinitionAllowed(Guid definingItemId, string name, string /// public static bool IsNewContainerIdAllowed(Guid definingItemId, string name, Guid newMetaDataContainerName) { - IEnumerable pageMetaDataDefinitions = DataFacade.GetData().Where(f => f.Name == name).Evaluate(); + var pageMetaDataDefinitions = DataFacade.GetData().Where(f => f.Name == name).Evaluate(); - IPageMetaDataDefinition pageMetaDataDefinition = pageMetaDataDefinitions.Where(f => f.DefiningItemId == definingItemId).SingleOrDefault(); - if ((pageMetaDataDefinition != null) && (pageMetaDataDefinition.MetaDataContainerId == newMetaDataContainerName)) + var pageMetaDataDefinition = pageMetaDataDefinitions.SingleOrDefault(f => f.DefiningItemId == definingItemId); + if (pageMetaDataDefinition != null && pageMetaDataDefinition.MetaDataContainerId == newMetaDataContainerName) { return true; // Return true if no changes are made } - if (pageMetaDataDefinitions.Count() > 1) return false; - - return true; + return pageMetaDataDefinitions.Count <= 1; } @@ -826,7 +837,7 @@ public static void RemoveDefinition(Guid definingItemId, string definitionName, - private static void RemoveDefinitionDeleteData(string definitionName, Type metaDataType, IEnumerable otherPageMetaDataDefintions) + private static void RemoveDefinitionDeleteData(string definitionName, Type metaDataType, IEnumerable otherPageMetaDataDefinitions) { IEnumerable dataToDelete = PageMetaDataFacade.GetMetaData(definitionName, metaDataType).Evaluate(); @@ -839,7 +850,7 @@ private static void RemoveDefinitionDeleteData(string definitionName, Type metaD continue; } - bool existsINOtherScope = ExistInOtherScope(page, otherPageMetaDataDefintions); + bool existsINOtherScope = ExistInOtherScope(page, otherPageMetaDataDefinitions); if (existsINOtherScope) { datasNotToDelete.Add(data); @@ -899,6 +910,9 @@ public static void AssignMetaDataSpecificValues(IData metaData, string metaDataD PropertyInfo pageReferencePropertyInfo = GetDefinitionPageReferencePropertyInfo(interfaceType); pageReferencePropertyInfo.SetValue(metaData, definingPage.Id, null); + + PropertyInfo pageReferencePropertyVersionInfo = GetDefinitionPageReferencePropertyVersionInfo(interfaceType); + pageReferencePropertyVersionInfo.SetValue(metaData, definingPage.VersionId, null); } @@ -917,6 +931,11 @@ public static PropertyInfo GetDefinitionPageReferencePropertyInfo(Type metaDataT return metaDataType.GetPropertiesRecursively().Last(f => f.Name == MetaDataType_PageReferenceFieldName); } + /// + public static PropertyInfo GetDefinitionPageReferencePropertyVersionInfo(Type metaDataType) + { + return metaDataType.GetPropertiesRecursively().Last(f => f.Name == MetaDataType_PageReferenceFieldVersionName); + } /// @@ -943,7 +962,7 @@ public static IPage GetMetaDataReferencedPage(this IData metaData) private static Guid GetPageIdOrNull(this IPage page) { - return page != null ? page.Id : Guid.Empty; + return page?.Id ?? Guid.Empty; } } } diff --git a/Composite/Data/ProcessControlled/ProcessControllerFacade.cs b/Composite/Data/ProcessControlled/ProcessControllerFacade.cs index 1aac3f18ba..92a831a4c1 100644 --- a/Composite/Data/ProcessControlled/ProcessControllerFacade.cs +++ b/Composite/Data/ProcessControlled/ProcessControllerFacade.cs @@ -43,22 +43,31 @@ static ProcessControllerFacade() /// /// public static void FullDelete(IData data) + { + FullDelete(new[] {data}); + } + + + internal static void FullDelete(IEnumerable dataset) { using (var transactionScope = TransactionsFacade.CreateNewScope()) { - using (new DataScope(DataScopeIdentifier.Administrated)) + foreach (var data in dataset) { if (data is IPublishControlled) { using (new DataScope(DataScopeIdentifier.Public)) - { + { IEnumerable datasDelete = DataFacade.GetDataFromOtherScope(data, DataScopeIdentifier.Public).Evaluate(); - + DataFacade.Delete(datasDelete, CascadeDeleteType.Disable); } } - DataFacade.Delete(data); + using (new DataScope(DataScopeIdentifier.Administrated)) + { + DataFacade.Delete(data); + } } transactionScope.Complete(); diff --git a/Composite/Data/ProcessControlled/ProcessControllers/GenericPublishProcessController/GenericPublishProcessController.cs b/Composite/Data/ProcessControlled/ProcessControllers/GenericPublishProcessController/GenericPublishProcessController.cs index 6abfc48b92..c72f2dd4f3 100644 --- a/Composite/Data/ProcessControlled/ProcessControllers/GenericPublishProcessController/GenericPublishProcessController.cs +++ b/Composite/Data/ProcessControlled/ProcessControllers/GenericPublishProcessController/GenericPublishProcessController.cs @@ -18,6 +18,8 @@ using Composite.Data.Types; +using ManagementStrings = Composite.Core.ResourceSystem.LocalizationFiles.Composite_Management; + namespace Composite.Data.ProcessControlled.ProcessControllers.GenericPublishProcessController { /// @@ -40,7 +42,7 @@ public sealed class GenericPublishProcessController : IPublishProcessController /// public const string Published = "published"; - private static readonly string _bulkPublishingCommands = "BulkPublishingCommands"; + public static string BulkPublishingCommandsTag { get; } = "BulkPublishingCommands"; private static readonly string _backToAwaitingApproval = "awaitingApprovalBack"; private static readonly string _forwardToAwaitingApproval = "awaitingApprovalForward"; @@ -109,10 +111,10 @@ public GenericPublishProcessController() _transitionNames = new Dictionary { - {Draft, StringResourceSystemFacade.GetString("Composite.Management", "PublishingStatus.draft")}, - {AwaitingApproval, StringResourceSystemFacade.GetString("Composite.Management", "PublishingStatus.awaitingApproval")}, - {AwaitingPublication, StringResourceSystemFacade.GetString("Composite.Management", "PublishingStatus.awaitingPublication")}, - {Published, StringResourceSystemFacade.GetString("Composite.Management", "PublishingStatus.published")} + {Draft, ManagementStrings.PublishingStatus_draft}, + {AwaitingApproval, ManagementStrings.PublishingStatus_awaitingApproval}, + {AwaitingPublication, ManagementStrings.PublishingStatus_awaitingPublication}, + {Published, ManagementStrings.PublishingStatus_published} }; Func sendBackToDraftAction = () => new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.SendToDraft) { DoIgnoreEntityTokenLocking = true })) @@ -131,7 +133,7 @@ public GenericPublishProcessController() ActionGroup = WorkflowActionGroup } }, - TagValue = _bulkPublishingCommands + TagValue = BulkPublishingCommandsTag }; @@ -151,7 +153,7 @@ public GenericPublishProcessController() ActionGroup = WorkflowActionGroup } }, - TagValue = _bulkPublishingCommands + TagValue = BulkPublishingCommandsTag }; @@ -171,7 +173,7 @@ public GenericPublishProcessController() ActionGroup = WorkflowActionGroup } }, - TagValue = _bulkPublishingCommands + TagValue = BulkPublishingCommandsTag }; @@ -193,11 +195,12 @@ public GenericPublishProcessController() ActionType = ActionType.Other, IsInFolder = false, IsInToolbar = true, - ActionGroup = WorkflowActionGroup + ActionGroup = WorkflowActionGroup, + ActionBundle = "Publish" } }, - TagValue = _bulkPublishingCommands - }; + TagValue = BulkPublishingCommandsTag + }; // "arrow pointing left when state change is going backwards" actions @@ -217,7 +220,7 @@ public GenericPublishProcessController() ActionGroup = WorkflowActionGroup } }, - TagValue = _bulkPublishingCommands + TagValue = BulkPublishingCommandsTag }; @@ -237,7 +240,7 @@ public GenericPublishProcessController() ActionGroup = WorkflowActionGroup } }, - TagValue = _bulkPublishingCommands, + TagValue = BulkPublishingCommandsTag, }; @@ -258,7 +261,7 @@ public GenericPublishProcessController() ActionGroup = WorkflowActionGroup } }, - TagValue = _bulkPublishingCommands + TagValue = BulkPublishingCommandsTag }; @@ -278,7 +281,7 @@ public GenericPublishProcessController() ActionGroup = WorkflowActionGroup } }, - TagValue = _bulkPublishingCommands + TagValue = BulkPublishingCommandsTag }; @@ -298,10 +301,11 @@ public GenericPublishProcessController() ActionGroup = WorkflowActionGroup } }, - TagValue = _bulkPublishingCommands + TagValue = BulkPublishingCommandsTag }; + Func publishActionDisabled = () => new ElementAction(new ActionHandle(new DisabledActionToken())) { VisualData = new ActionVisualizedData @@ -318,7 +322,7 @@ public GenericPublishProcessController() ActionGroup = WorkflowActionGroup } }, - TagValue = _bulkPublishingCommands + TagValue = BulkPublishingCommandsTag }; _visualTransitionsActions = new Dictionary> @@ -356,17 +360,21 @@ public List GetActions(IData data, Type elementProviderType) var publishControlled = (IPublishControlled)data; - IList visualTrans = _visualTransitions[publishControlled.PublicationStatus]; + IList visualTrans; + if (!_visualTransitions.TryGetValue(publishControlled.PublicationStatus, out visualTrans)) + { + throw new InvalidOperationException($"Unknown publication state '{publishControlled.PublicationStatus}'"); + } var clientActions = visualTrans.Select(newState => _visualTransitionsActions[newState]()).ToList(); - IData publicData = DataFacade.GetDataFromOtherScope(data, DataScopeIdentifier.Public, true).FirstOrDefault(); + IData publicData = DataFacade.GetDataFromOtherScope(data, DataScopeIdentifier.Public, true, false).FirstOrDefault(); if (publicData != null) { var unpublishAction = new ElementAction(new ActionHandle(new ProxyDataActionToken(ActionIdentifier.Unpublish) { DoIgnoreEntityTokenLocking = true })) { - VisualData = new ActionVisualizedData() + VisualData = new ActionVisualizedData { Label = StringResourceSystemFacade.GetString("Composite.Plugins.GenericPublishProcessController", "Unpublish"), ToolTip = StringResourceSystemFacade.GetString("Composite.Plugins.GenericPublishProcessController", "UnpublishToolTip"), diff --git a/Composite/Data/Types/Foundation/PagePublishControlledAuxiliary.cs b/Composite/Data/Types/Foundation/PagePublishControlledAuxiliary.cs index 24b70072e1..2b450d9f61 100644 --- a/Composite/Data/Types/Foundation/PagePublishControlledAuxiliary.cs +++ b/Composite/Data/Types/Foundation/PagePublishControlledAuxiliary.cs @@ -19,7 +19,7 @@ public void OnAfterDataUpdated(IData data) { pagePlaceholderContents = (from content in DataFacade.GetData() - where content.PageId == page.Id + where content.PageId == page.Id && content.VersionId == page.VersionId select content).ToList(); } @@ -29,7 +29,8 @@ public void OnAfterDataUpdated(IData data) { using (new DataScope(DataScopeIdentifier.Public)) { - DataFacade.Delete(f => f.PageId == page.Id); + DataFacade.Delete( + f => f.PageId == page.Id && f.VersionId == page.VersionId); } foreach (var pagePlaceholderContent in pagePlaceholderContents) diff --git a/Composite/Data/Types/IPage.cs b/Composite/Data/Types/IPage.cs index 04c43e3aa7..a9613af014 100644 --- a/Composite/Data/Types/IPage.cs +++ b/Composite/Data/Types/IPage.cs @@ -18,17 +18,17 @@ namespace Composite.Data.Types [Title("C1 Page")] [AutoUpdateble] [ImmutableTypeId("{C046F704-D3E4-4b3d-8CB9-77564FB0B9E7}")] - [KeyPropertyName("Id")] + [KeyPropertyName(nameof(Id))] [DataAncestorProvider(typeof(PageDataAncestorProvider))] [DataScope(DataScopeIdentifier.PublicName)] [DataScope(DataScopeIdentifier.AdministratedName)] - [LabelPropertyName("Title")] + [LabelPropertyName(nameof(Title))] [RelevantToUserType(UserType.Developer)] [CachingAttribute(CachingType.Full)] [PublishControlledAuxiliary(typeof(PagePublishControlledAuxiliary))] [PublishProcessControllerTypeAttribute(typeof(GenericPublishProcessController))] [KeyTemplatedXhtmlRenderer(XhtmlRenderingType.Embedable, "{label}")] - public interface IPage : IData, IChangeHistory,ICreationHistory, IPublishControlled, ILocalizedControlled + public interface IPage : IData, IChangeHistory, ICreationHistory, IPublishControlled, ILocalizedControlled, IVersioned { /// [StoreFieldType(PhysicalStoreFieldType.Guid)] diff --git a/Composite/Data/Types/IPagePlaceholderContent.cs b/Composite/Data/Types/IPagePlaceholderContent.cs index 024420a0e4..37e86671ea 100644 --- a/Composite/Data/Types/IPagePlaceholderContent.cs +++ b/Composite/Data/Types/IPagePlaceholderContent.cs @@ -14,28 +14,28 @@ namespace Composite.Data.Types [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] [AutoUpdateble] [ImmutableTypeId("{3EAA3814-04E6-4c7f-8F1A-004A89BB0848}")] - [KeyPropertyName(0, "PageId")] - [KeyPropertyName(1, "PlaceHolderId")] + [KeyPropertyName(0, nameof(PageId))] + [KeyPropertyName(1, nameof(PlaceHolderId))] [DataAncestorProvider(typeof(PropertyDataAncestorProvider))] - [PropertyDataAncestorProvider("PageId", typeof(IPage), "Id", null)] + [PropertyDataAncestorProvider(nameof(PageId), typeof(IPage), nameof(IPage.Id), null)] [DataScope(DataScopeIdentifier.PublicName)] [DataScope(DataScopeIdentifier.AdministratedName)] [CachingAttribute(CachingType.Full)] [PublishProcessControllerTypeAttribute(typeof(GenericPublishProcessController))] [Title("C1 Page Content")] - public interface IPagePlaceholderContent : IData, IChangeHistory,ICreationHistory, IPublishControlled, ILocalizedControlled + public interface IPagePlaceholderContent : IData, IChangeHistory, ICreationHistory, IPublishControlled, ILocalizedControlled, IVersioned { /// [StoreFieldType(PhysicalStoreFieldType.Guid)] [ImmutableFieldId("{19DFF302-F089-4900-8B64-35F88C82EC45}")] - [ForeignKey(typeof(IPage), "Id", AllowCascadeDeletes = true)] + [ForeignKey(typeof(IPage), nameof(IPage.Id), AllowCascadeDeletes = true)] Guid PageId { get; set; } /// [StoreFieldType(PhysicalStoreFieldType.String, 255)] [ImmutableFieldId("{D8243AA6-A02A-4383-9ED1-2A7C1A8841E2}")] - [NotNullValidator()] + [NotNullValidator] string PlaceHolderId { get; set; } diff --git a/Composite/Data/Types/IVersioned.cs b/Composite/Data/Types/IVersioned.cs new file mode 100644 index 0000000000..f5dd0a9699 --- /dev/null +++ b/Composite/Data/Types/IVersioned.cs @@ -0,0 +1,17 @@ +using System; + +namespace Composite.Data.Types +{ + /// + /// Represents a data type that supports multiple versions of the same data item + /// + [VersionKeyPropertyName(nameof(VersionId))] + public interface IVersioned : IData + { + /// + [StoreFieldType(PhysicalStoreFieldType.Guid)] + [ImmutableFieldId("{f42d511b-1d76-4c05-a895-99f23b757e1e}")] + [DefaultFieldNewGuidValue] + Guid VersionId { get; set; } + } +} diff --git a/Composite/Data/Types/IVersionedDataHelper.cs b/Composite/Data/Types/IVersionedDataHelper.cs new file mode 100644 index 0000000000..6cb42f691d --- /dev/null +++ b/Composite/Data/Types/IVersionedDataHelper.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Composite.Data.Types +{ + /// + /// Contract for defining IVersioned extra methods and helper functions + /// + public abstract class VersionedDataHelperContract + { + /// + /// Returns version name for the IVersioned data if it could otherwise returns null + /// + public abstract string LocalizedVersionName(T data) where T : IVersioned; + + /// + /// Returns currently live version name for the IVersioned data if it could otherwise returns null + /// + public abstract string GetLiveVersionName(T data) where T : IVersioned; + + /// + /// Returns column name and tooltip for the extra fields in publication overview, if no extra fields needed returns null + /// + public abstract List GetExtraPropertiesNames(); + + /// + /// Returns values for the extra fields in publication overview, if no extra fields needed returns null + /// + public abstract List GetExtraProperties(T data) where T : IVersioned; + + } + + /// + /// This class should be used in every versioning package to register it's naming and detecting of live versions + /// + public static class VersionedDataHelper + { + private static List _instances; + + static VersionedDataHelper() + { + DataEvents.OnBeforeAdd += (sender, args) => + { + var page = (IPage) args.Data; + if (page.VersionId == Guid.Empty) + { + page.VersionId = Guid.NewGuid(); + } + }; + } + + internal static void Initialize() + { + // The initialization code is in the static constructor + } + + /// + /// Returns if there are any versioning package instances available + /// + public static bool IsThereAnyVersioningServices => _instances!=null && _instances.Count > 0; + + /// + /// Registers instances of versioning packages + /// + public static void RegisterVersionHelper(VersionedDataHelperContract vpc) + { + if (_instances == null) + { + _instances = new List(); + } + + _instances.Add(vpc); + } + + /// + /// Returns version name for the IVersioned data + /// + public static string LocalizedVersionName(this T str) where T : IVersioned + { + var defaultVersionName = + Core.ResourceSystem.LocalizationFiles.Composite_Management.DefaultVersionName; + + if (_instances == null) + { + return defaultVersionName; + } + + return _instances.Select(p => p.LocalizedVersionName(str)).Any(name => name != null)? + string.Join(",", _instances.Select(p => p.LocalizedVersionName(str)).Where(name => name != null)): defaultVersionName; + } + + /// + /// Returns column name and tooltip for the extra fields in publication overview + /// + public static List GetExtraPropertiesNames() + { + return _instances?.SelectMany(p => p.GetExtraPropertiesNames() ?? new List()).ToList(); + } + + /// + /// Returns values for the extra fields in publication overview + /// + public static List GetExtraProperties(this T str) where T : IVersioned + { + return _instances?.SelectMany(p => p.GetExtraProperties(str) ?? new List()).ToList(); + } + + /// + /// Returns currently live version name for the IVersioned data + /// + public static string GetLiveVersionName(this T str) where T : IVersioned + { + if (_instances == null) + { + return null; + } + + var versionNames = _instances.Select(p => p.GetLiveVersionName(str)).Where(name => name != null).ToList(); + return versionNames.Any() ? string.Join(",", versionNames) : null; + } + + } + + /// + /// Represents Extra fields that a Versioning package needs to insert to the publication overview + /// + public class VersionedExtraProperties + { + /// + public string ColumnName; + /// + public string Value; + /// + public string SortableValue; + } + + /// + /// Represents column title and tooltip for the Extra fields that a Versioning package needs to insert to the publication overview + /// + public class VersionedExtraPropertiesColumnInfo + { + /// + public string ColumnName; + /// + public string ColumnTooltip; + } +} diff --git a/Composite/Data/Types/PageInsertPosition.cs b/Composite/Data/Types/PageInsertPosition.cs index cfae48e1df..4f908c1d74 100644 --- a/Composite/Data/Types/PageInsertPosition.cs +++ b/Composite/Data/Types/PageInsertPosition.cs @@ -46,6 +46,9 @@ internal class BottomPageInsertPosition : IPageInsertionPosition { public void CreatePageStructure(IPage page, Guid parentPageId) { + if (DataFacade.GetData(f => f.Id == page.Id).Any()) + return; + int siblingPageCount = (from ps in DataFacade.GetData() where ps.ParentId == parentPageId @@ -64,6 +67,9 @@ internal class TopPageInsertPosition : IPageInsertionPosition { public void CreatePageStructure(IPage page, Guid parentPageId) { + if (DataFacade.GetData(f => f.Id == page.Id).Any()) + return; + PageServices.InsertIntoPositionInternal(page.Id, parentPageId, 0); } } @@ -72,6 +78,9 @@ internal class AlphabeticPageInsertPosition : IPageInsertionPosition { public void CreatePageStructure(IPage newPage, Guid parentPageId) { + if (DataFacade.GetData(f => f.Id == newPage.Id).Any()) + return; + List pageStructures = (from ps in DataFacade.GetData() where ps.ParentId == parentPageId @@ -135,6 +144,9 @@ public AfterPageInsertPosition(Guid existingPageId) public void CreatePageStructure(IPage newPage, Guid parentPageId) { + if (DataFacade.GetData(f => f.Id == newPage.Id).Any()) + return; + var pageStructures = (from ps in DataFacade.GetData() where ps.ParentId == parentPageId diff --git a/Composite/Data/Types/PageServices.cs b/Composite/Data/Types/PageServices.cs index 64edf2382a..c1304f40cd 100644 --- a/Composite/Data/Types/PageServices.cs +++ b/Composite/Data/Types/PageServices.cs @@ -5,6 +5,8 @@ using Composite.C1Console.Trees; using Composite.C1Console.Users; using Composite.Core.Linq; +using Composite.Data.ProcessControlled; +using Composite.Data.Transactions; namespace Composite.Data.Types @@ -56,20 +58,13 @@ public static IQueryable GetChildren(this IPage page) /// public static IQueryable GetChildren(Guid parentId) { - var pageIDs = PageManager.GetChildrenIDs(parentId); + return from ps in DataFacade.GetData() + join p in DataFacade.GetData() on ps.Id equals p.Id + where ps.ParentId == parentId + orderby ps.LocalOrdering + select p; - var result = new List(); - foreach (var id in pageIDs) - { - var page = PageManager.GetPageById(id); - // A page can de deleted after getting the child list, in a separate thread - if (page != null) - { - result.Add(page); - } - } - - return result.AsQueryable(); +#warning revisit this - we return all versions (by design so far). Any ordering on page versions? - check history for original intent } @@ -305,10 +300,10 @@ public static IPage InsertIntoPosition(this IPage newPage, Guid parentId, int lo internal static void InsertIntoPositionInternal(Guid newPageId, Guid parentId, int localOrder) { List pageStructures = - (from ps in DataFacade.GetData(false) - where ps.ParentId == parentId - orderby ps.LocalOrdering - select ps).ToList(); + (from ps in DataFacade.GetData(false) + where ps.ParentId == parentId + orderby ps.LocalOrdering + select ps).ToList(); var toBeUpdated = new List(); for (int i = 0; i < pageStructures.Count; i++) @@ -478,6 +473,7 @@ public static void AddPageTypeRelatedData(IPage page) { IPagePlaceholderContent pagePlaceholderContent = DataFacade.BuildNew(); pagePlaceholderContent.PageId = page.Id; + pagePlaceholderContent.VersionId = page.VersionId; pagePlaceholderContent.PlaceHolderId = pageTypeDefaultPageContent.PlaceHolderId; pagePlaceholderContent.Content = pageTypeDefaultPageContent.Content; DataFacade.AddNew(pagePlaceholderContent); @@ -486,9 +482,131 @@ public static void AddPageTypeRelatedData(IPage page) AddPageTypePageFoldersAndApplications(page); } + /// + /// Deletes the versions of the given page in its current localization scope. + /// + public static void DeletePage(IPage page) + { + using (var transactionScope = TransactionsFacade.CreateNewScope()) + { + List cultures = DataLocalizationFacade.ActiveLocalizationCultures.ToList(); + cultures.Remove(page.DataSourceId.LocaleScope); + + List pagesToDelete = page.GetSubChildren().ToList(); + + foreach (IPage childPage in pagesToDelete) + { + if (!ExistInOtherLocale(cultures, childPage)) + { + RemoveAllFolderAndMetaDataDefinitions(childPage); + } + + childPage.DeletePageStructure(); + ProcessControllerFacade.FullDelete(childPage); + } + + + if (!ExistInOtherLocale(cultures, page)) + { + RemoveAllFolderAndMetaDataDefinitions(page); + } + + page.DeletePageStructure(); + + Guid pageId = page.Id; + var pageVersions = DataFacade.GetData(p => p.Id == pageId).ToList(); + + ProcessControllerFacade.FullDelete(pageVersions); + + transactionScope.Complete(); + } + } + + private static bool ExistInOtherLocale(List cultures, IPage page) + { + foreach (CultureInfo localeCultureInfo in cultures) + { + using (new DataScope(localeCultureInfo)) + { + if (Composite.Data.PageManager.GetPageById(page.Id) != null) + { + return true; + } + } + } + + return false; + } + + + private static void RemoveAllFolderAndMetaDataDefinitions(IPage page) + { + foreach (Type folderType in page.GetDefinedFolderTypes()) + { + page.RemoveFolderDefinition(folderType, true); + } + + foreach (Tuple metaDataTypeAndName in page.GetDefinedMetaDataTypeAndNames()) + { + page.RemoveMetaDataDefinition(metaDataTypeAndName.Item2, true); + } + } + + /// + /// Delete the specific version of the page in the current localization scope. + /// + /// + /// + /// + public static void DeletePage(Guid pageId, Guid versionId, CultureInfo locale) + { + Verify.ArgumentNotNull(locale, nameof(locale)); + + using (var conn = new DataConnection(PublicationScope.Unpublished, locale)) + { + var pages = conn.Get().Where(p => p.Id == pageId).ToList(); + if (pages.Count == 1 && pages[0].VersionId == versionId) + { + DeletePage(pages[0]); + return; + } + } + + var publicationScopes = new[] {PublicationScope.Published, PublicationScope.Unpublished}; + + using (var transactionScope = TransactionsFacade.CreateNewScope()) + { + foreach (var publicationScope in publicationScopes) + { + using (var conn = new DataConnection(publicationScope, locale)) + { + var pageToDelete = conn.Get() + .SingleOrDefault(p => p.Id == pageId && p.VersionId == versionId); + + var placeholders = conn.Get() + .Where(p => p.PageId == pageId && p.VersionId == versionId).ToList(); + + if (placeholders.Any()) + { + DataFacade.Delete(placeholders, false, false); + } + + if (pageToDelete != null) + { + DataFacade.Delete(pageToDelete); + } + } + } + + transactionScope.Complete(); + } + } + internal static bool AddPageTypePageFoldersAndApplications(IPage page) { +#warning Validate that having a page type with associated PageType PageFolders or Applications does not break on 2nd add for same page id + Guid pageTypeId = page.PageTypeId; bool treeRefreshindNeeded = false; diff --git a/Composite/Data/VersionKeyPropertyName.cs b/Composite/Data/VersionKeyPropertyName.cs new file mode 100644 index 0000000000..462d740108 --- /dev/null +++ b/Composite/Data/VersionKeyPropertyName.cs @@ -0,0 +1,18 @@ +using System; + +namespace Composite.Data +{ + /// + [AttributeUsage(AttributeTargets.Interface, AllowMultiple = true, Inherited = true)] + public sealed class VersionKeyPropertyNameAttribute : Attribute + { + /// + public VersionKeyPropertyNameAttribute(string propertyName) + { + this.VersionKeyPropertyName = propertyName; + } + + /// + public string VersionKeyPropertyName { get; } + } +} diff --git a/Composite/Plugins/Commands/ConsoleCommandHandlers/FocusData.cs b/Composite/Plugins/Commands/ConsoleCommandHandlers/FocusData.cs index 02f0ad4999..09000fa066 100644 --- a/Composite/Plugins/Commands/ConsoleCommandHandlers/FocusData.cs +++ b/Composite/Plugins/Commands/ConsoleCommandHandlers/FocusData.cs @@ -29,7 +29,7 @@ public void HandleConsoleCommand(string consoleId, string commandPayload) return; } - var keyProperty = type.GetKeyProperties().Single(); + var keyProperty = type.GetSingleKeyProperty(); object key = ValueTypeConverter.Convert(keyString, keyProperty.PropertyType); diff --git a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/CodeGeneration/DataIdClassGenerator.cs b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/CodeGeneration/DataIdClassGenerator.cs index ee23566b44..c226d691b0 100644 --- a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/CodeGeneration/DataIdClassGenerator.cs +++ b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/CodeGeneration/DataIdClassGenerator.cs @@ -51,7 +51,7 @@ private void AddConstructor(CodeTypeDeclaration declaration) { var constructor = new CodeConstructor { Attributes = MemberAttributes.Public | MemberAttributes.Final }; - foreach (var keyField in _dataTypeDescriptor.KeyFields) + foreach (var keyField in _dataTypeDescriptor.PhysicalKeyFields) { Type keyPropertyType = keyField.InstanceType; @@ -67,9 +67,10 @@ private void AddConstructor(CodeTypeDeclaration declaration) private void AddProperties(CodeTypeDeclaration declaration) { - foreach (string keyPropertyName in _dataTypeDescriptor.KeyPropertyNames) + foreach (var keyProperty in _dataTypeDescriptor.PhysicalKeyFields) { - Type keyPropertyType = _dataTypeDescriptor.Fields[keyPropertyName].InstanceType; + string keyPropertyName = keyProperty.Name; + Type keyPropertyType = keyProperty.InstanceType; string propertyFieldName = MakePropertyFieldName(keyPropertyName); declaration.Members.Add(new CodeMemberField(keyPropertyType, propertyFieldName)); diff --git a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/CodeGeneration/EntityBaseClassGenerator.cs b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/CodeGeneration/EntityBaseClassGenerator.cs index 7562ba9ee2..5966622d99 100644 --- a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/CodeGeneration/EntityBaseClassGenerator.cs +++ b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/CodeGeneration/EntityBaseClassGenerator.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Globalization; +using System.Linq; using System.Reflection; using Composite.Core.Types; using Composite.Data; @@ -29,10 +30,12 @@ public EntityBaseClassGenerator(DataTypeDescriptor dataTypeDescriptor, string en public CodeTypeDeclaration CreateClass() { - CodeTypeDeclaration codeTypeDeclaration = new CodeTypeDeclaration(_entityBaseClassName); + var codeTypeDeclaration = new CodeTypeDeclaration(_entityBaseClassName) + { + IsClass = true, + TypeAttributes = TypeAttributes.Public | TypeAttributes.Abstract + }; - codeTypeDeclaration.IsClass = true; - codeTypeDeclaration.TypeAttributes = TypeAttributes.Public | TypeAttributes.Abstract; codeTypeDeclaration.BaseTypes.Add(typeof(INotifyPropertyChanged)); codeTypeDeclaration.BaseTypes.Add(typeof(INotifyPropertyChanging)); codeTypeDeclaration.BaseTypes.Add(typeof(IEntity)); @@ -58,8 +61,10 @@ public CodeTypeDeclaration CreateClass() private static void AddConstructor(CodeTypeDeclaration declaration) { - CodeConstructor constructor = new CodeConstructor(); - constructor.Attributes = MemberAttributes.Public; + var constructor = new CodeConstructor + { + Attributes = MemberAttributes.Public + }; constructor.Statements.Add( new CodeAssignStatement( @@ -78,16 +83,18 @@ private static void AddConstructor(CodeTypeDeclaration declaration) private void AddIEntityImplementation(CodeTypeDeclaration declaration) { - CodeMemberMethod method = new CodeMemberMethod(); - method.Name = "Commit"; - method.Attributes = MemberAttributes.Public | MemberAttributes.Final; + var method = new CodeMemberMethod + { + Name = "Commit", + Attributes = MemberAttributes.Public | MemberAttributes.Final + }; foreach (DataFieldDescriptor dataFieldDescriptor in _dataTypeDescriptor.Fields) { string propertyName = dataFieldDescriptor.Name; - string fieldName = string.Format("_{0}", propertyName); - string nullableFieldName = string.Format("_{0}Nullable", propertyName); + string fieldName = $"_{propertyName}"; + string nullableFieldName = $"_{propertyName}Nullable"; method.Statements.Add( new CodeConditionStatement( @@ -144,17 +151,19 @@ private void AddIEntityImplementation(CodeTypeDeclaration declaration) private void AddIDataSourceProperty(CodeTypeDeclaration declaration) { - PropertyInfo propertyInfo = typeof(IData).GetProperty("DataSourceId"); - - CodeMemberProperty codeProperty = new CodeMemberProperty(); - codeProperty.Attributes = MemberAttributes.Public | MemberAttributes.Final; - codeProperty.Name = propertyInfo.Name; - codeProperty.HasGet = true; - codeProperty.HasSet = false; - codeProperty.Type = new CodeTypeReference(propertyInfo.PropertyType); + PropertyInfo propertyInfo = typeof(IData).GetProperty(nameof(IData.DataSourceId)); - List dataIdConstructorParms = new List(); - foreach (string propertyName in _dataTypeDescriptor.KeyPropertyNames) + var codeProperty = new CodeMemberProperty + { + Attributes = MemberAttributes.Public | MemberAttributes.Final, + Name = propertyInfo.Name, + HasGet = true, + HasSet = false, + Type = new CodeTypeReference(propertyInfo.PropertyType) + }; + + var dataIdConstructorParms = new List(); + foreach (string propertyName in _dataTypeDescriptor.PhysicalKeyFields.Select(f=>f.Name)) { dataIdConstructorParms.Add( new CodePropertyReferenceExpression( @@ -221,8 +230,8 @@ private void AddProperties(CodeTypeDeclaration declaration) string propertyName = dataFieldDescriptor.Name; Type propertyType = dataFieldDescriptor.InstanceType; - string fieldName = string.Format("_{0}", propertyName); - string nullableFieldName = string.Format("_{0}Nullable", propertyName); + string fieldName = $"_{propertyName}"; + string nullableFieldName = $"_{propertyName}Nullable"; AddPropertiesAddField(declaration, propertyType, fieldName); AddPropertiesAddNullableField(declaration, propertyType, nullableFieldName); @@ -234,10 +243,12 @@ private void AddProperties(CodeTypeDeclaration declaration) private static void AddPropertiesAddField(CodeTypeDeclaration declaration, Type propertyType, string fieldName) { - CodeMemberField fieldMember = new CodeMemberField(); - fieldMember.Name = fieldName; - fieldMember.Type = new CodeTypeReference(propertyType); - fieldMember.Attributes = MemberAttributes.Family; + var fieldMember = new CodeMemberField + { + Name = fieldName, + Type = new CodeTypeReference(propertyType), + Attributes = MemberAttributes.Family + }; declaration.Members.Add(fieldMember); } @@ -246,12 +257,14 @@ private static void AddPropertiesAddField(CodeTypeDeclaration declaration, Type private static void AddPropertiesAddNullableField(CodeTypeDeclaration declaration, Type propertyType, string fieldName) { - CodeMemberField fieldMember = new CodeMemberField(); - fieldMember.Name = fieldName; - fieldMember.Type = new CodeTypeReference(typeof(ExtendedNullable<>).FullName, new CodeTypeReference(propertyType)); - fieldMember.Attributes = MemberAttributes.Family; + var fieldMember = new CodeMemberField + { + Name = fieldName, + Type = new CodeTypeReference(typeof (ExtendedNullable<>).FullName, new CodeTypeReference(propertyType)), + Attributes = MemberAttributes.Family, + InitExpression = new CodePrimitiveExpression(null) + }; - fieldMember.InitExpression = new CodePrimitiveExpression(null); declaration.Members.Add(fieldMember); } @@ -260,12 +273,14 @@ private static void AddPropertiesAddNullableField(CodeTypeDeclaration declaratio private static void AddPropertiesAddProperty(CodeTypeDeclaration declaration, string propertyName, Type propertyType, string fieldName, string nullableFieldName) { - CodeMemberProperty propertyMember = new CodeMemberProperty(); - propertyMember.Name = propertyName; - propertyMember.Type = new CodeTypeReference(propertyType); - propertyMember.Attributes = MemberAttributes.Public; - propertyMember.HasSet = true; - propertyMember.HasGet = true; + var propertyMember = new CodeMemberProperty + { + Name = propertyName, + Type = new CodeTypeReference(propertyType), + Attributes = MemberAttributes.Public, + HasSet = true, + HasGet = true + }; propertyMember.GetStatements.Add( diff --git a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/CodeGeneration/EntityClassGenerator.cs b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/CodeGeneration/EntityClassGenerator.cs index dff5b2cc0a..0f4a54c71e 100644 --- a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/CodeGeneration/EntityClassGenerator.cs +++ b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/CodeGeneration/EntityClassGenerator.cs @@ -222,24 +222,21 @@ private void AddPropertiesAddProperty(CodeTypeDeclaration declaration, string pr propertyMember.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(DebuggerNonUserCodeAttribute)))); - var codeAttributeArguments = new List { - new CodeAttributeArgument("Name", new CodePrimitiveExpression(dbName)), - new CodeAttributeArgument("Storage", new CodePrimitiveExpression(fieldName)), - new CodeAttributeArgument("DbType", new CodePrimitiveExpression(dbType)), - new CodeAttributeArgument("CanBeNull", new CodePrimitiveExpression(isNullable)), - new CodeAttributeArgument("IsPrimaryKey", new CodePrimitiveExpression(isId)), - new CodeAttributeArgument("IsDbGenerated", new CodePrimitiveExpression(isAutoGen)) - }; - - - codeAttributeArguments.Add( - new CodeAttributeArgument("UpdateCheck", - new CodeFieldReferenceExpression( - new CodeTypeReferenceExpression(typeof(UpdateCheck)), - "Never" - ) + var codeAttributeArguments = new List + { + new CodeAttributeArgument("Name", new CodePrimitiveExpression(dbName)), + new CodeAttributeArgument("Storage", new CodePrimitiveExpression(fieldName)), + new CodeAttributeArgument("DbType", new CodePrimitiveExpression(dbType)), + new CodeAttributeArgument("CanBeNull", new CodePrimitiveExpression(isNullable)), + new CodeAttributeArgument("IsPrimaryKey", new CodePrimitiveExpression(isId)), + new CodeAttributeArgument("IsDbGenerated", new CodePrimitiveExpression(isAutoGen)), + new CodeAttributeArgument("UpdateCheck", + new CodeFieldReferenceExpression( + new CodeTypeReferenceExpression(typeof (UpdateCheck)), nameof(UpdateCheck.Never)) ) - ); + }; + + propertyMember.CustomAttributes.Add(new CodeAttributeDeclaration( new CodeTypeReference(typeof(ColumnAttribute)), diff --git a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/CodeGeneration/SqlDataProviderCodeBuilder.cs b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/CodeGeneration/SqlDataProviderCodeBuilder.cs index c2a3d88cef..46cc5e1e42 100644 --- a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/CodeGeneration/SqlDataProviderCodeBuilder.cs +++ b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/CodeGeneration/SqlDataProviderCodeBuilder.cs @@ -57,7 +57,7 @@ internal void AddDataType(DataTypeDescriptor dataTypeDescriptor, IEnumerable(); var keyPropertiesList = new List>(); - foreach (var keyField in dataTypeDescriptor.KeyFields) + foreach (var keyField in dataTypeDescriptor.PhysicalKeyFields) { Verify.That(!keyPropertiesDictionary.ContainsKey(keyField.Name), "Key field with name '{0}' already present. Data type: {1}. Check for multiple [KeyPropertyName(...)] attributes", keyField.Name, dataTypeDescriptor.Namespace + "." + dataTypeDescriptor.Name); diff --git a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/CodeGeneration/SqlDataProviderHelperGenerator.cs b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/CodeGeneration/SqlDataProviderHelperGenerator.cs index eefcc5b055..8b3b88c9ed 100644 --- a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/CodeGeneration/SqlDataProviderHelperGenerator.cs +++ b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/CodeGeneration/SqlDataProviderHelperGenerator.cs @@ -35,28 +35,32 @@ public SqlDataProviderHelperGenerator(DataTypeDescriptor dataTypeDescriptor, str public CodeTypeDeclaration CreateClass() { - CodeTypeDeclaration declaration = new CodeTypeDeclaration(_sqlDataProviderHelperClassName); + var declaration = new CodeTypeDeclaration(_sqlDataProviderHelperClassName) + { + IsClass = true, + TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed + }; - declaration.IsClass = true; - declaration.TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed; declaration.BaseTypes.Add(typeof(ISqlDataProviderHelper)); - foreach (string keyFieldName in _dataTypeDescriptor.KeyPropertyNames) + foreach (string keyFieldName in _dataTypeDescriptor.PhysicalKeyPropertyNames) { string fieldName = CreateDataIdPropertyInfoFieldName(keyFieldName); - CodeMemberField codeField = new CodeMemberField(new CodeTypeReference(typeof(PropertyInfo)), fieldName); - codeField.InitExpression = - new CodeMethodInvokeExpression( + CodeMemberField codeField = new CodeMemberField(new CodeTypeReference(typeof (PropertyInfo)), fieldName) + { + InitExpression = new CodeMethodInvokeExpression( new CodeMethodReferenceExpression( - new CodeTypeReferenceExpression(typeof(IDataExtensions)), - "GetDataPropertyRecursivly" + new CodeTypeReferenceExpression(typeof (IDataExtensions)), + nameof(IDataExtensions.GetDataPropertyRecursively) ), - new CodeExpression[] { - new CodeTypeOfExpression(_entityClassName), - new CodePrimitiveExpression(keyFieldName) - } - ); + new CodeExpression[] + { + new CodeTypeOfExpression(_entityClassName), + new CodePrimitiveExpression(keyFieldName) + } + ) + }; declaration.Members.Add(codeField); } @@ -133,8 +137,8 @@ private void AddGetDataByIdMethod(CodeTypeDeclaration declaration) // where body variable - CodeExpression currentExpresion = null; - foreach (string propertyName in _dataTypeDescriptor.KeyPropertyNames) + CodeExpression currentExpression = null; + foreach (string propertyName in _dataTypeDescriptor.PhysicalKeyPropertyNames) { CodeExpression newExpression = new CodeMethodInvokeExpression( new CodeTypeReferenceExpression(typeof(Expression)), @@ -164,17 +168,17 @@ private void AddGetDataByIdMethod(CodeTypeDeclaration declaration) } ); - if (currentExpresion == null) + if (currentExpression == null) { - currentExpresion = newExpression; + currentExpression = newExpression; } else { - currentExpresion = new CodeMethodInvokeExpression( + currentExpression = new CodeMethodInvokeExpression( new CodeTypeReferenceExpression(typeof(Expression)), "And", new [] { - currentExpresion, + currentExpression, newExpression } ); @@ -185,11 +189,11 @@ private void AddGetDataByIdMethod(CodeTypeDeclaration declaration) new CodeVariableDeclarationStatement( new CodeTypeReference(typeof(Expression)), whereBodyExpressionVariableName, - currentExpresion + currentExpression )); - // where labmda variable + // where lambda variable codeMethod.Statements.Add( new CodeVariableDeclarationStatement( new CodeTypeReference(typeof(LambdaExpression)), @@ -429,7 +433,7 @@ private void AddRemoveDataMethod(CodeTypeDeclaration declaration) private static string CreateDataIdPropertyInfoFieldName(string propertyName) { - return string.Format("_dataIdEntityPropertyInfo{0}", propertyName); + return $"_dataIdEntityPropertyInfo{propertyName}"; } } } diff --git a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/Foundation/InterfaceConfigurationManipulator.cs b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/Foundation/InterfaceConfigurationManipulator.cs index ec877daf4c..b00ba3ce89 100644 --- a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/Foundation/InterfaceConfigurationManipulator.cs +++ b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/Foundation/InterfaceConfigurationManipulator.cs @@ -139,7 +139,7 @@ private static InterfaceConfigurationElement BuildInterfaceConfigurationElement( //} var keyInfo = new SimpleNameTypeConfigurationElementCollection(); - foreach (DataFieldDescriptor field in dataTypeDescriptor.KeyFields) + foreach (DataFieldDescriptor field in dataTypeDescriptor.PhysicalKeyFields) { keyInfo.Add(field.Name, field.InstanceType); } diff --git a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/Foundation/SqlDataProviderStoreManipulator.cs b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/Foundation/SqlDataProviderStoreManipulator.cs index 895b312df9..bfa26150d9 100644 --- a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/Foundation/SqlDataProviderStoreManipulator.cs +++ b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/Foundation/SqlDataProviderStoreManipulator.cs @@ -13,6 +13,7 @@ using Composite.Data; using Composite.Data.DynamicTypes; using Composite.Data.ProcessControlled.ProcessControllers.GenericPublishProcessController; +using Composite.Data.Types; using Composite.Plugins.Data.DataProviders.MSSqlServerDataProvider.Sql; @@ -105,7 +106,7 @@ internal void CreateStore(DataTypeDescriptor typeDescriptor, DataScopeIdentifier ).ToList(); sql.AppendFormat("CREATE TABLE dbo.[{0}]({1});", tableName, string.Join(",", sqlColumns)); - sql.Append(SetPrimaryKey(tableName, typeDescriptor.KeyPropertyNames, typeDescriptor.PrimaryKeyIsClusteredIndex)); + sql.Append(SetPrimaryKey(tableName, typeDescriptor.PhysicalKeyPropertyNames, typeDescriptor.PrimaryKeyIsClusteredIndex)); try { @@ -454,7 +455,7 @@ private void AlterStore(UpdateDataTypeDescriptor updateDataTypeDescriptor, DataT }; } - AppendFields(alteredTableName, changeDescriptor.AddedFields, defaultValues); + AppendFields(alteredTableName, changeDescriptor, changeDescriptor.AddedFields, defaultValues); // Clustered index has to be created first. var createIndexActions = new List>(); @@ -464,7 +465,7 @@ private void AlterStore(UpdateDataTypeDescriptor updateDataTypeDescriptor, DataT bool isClusteredIndex = changeDescriptor.AlteredType.PrimaryKeyIsClusteredIndex; createIndexActions.Add(new Tuple(isClusteredIndex, - () => ExecuteNonQuery(SetPrimaryKey(alteredTableName, changeDescriptor.AlteredType.KeyPropertyNames, isClusteredIndex)) + () => ExecuteNonQuery(SetPrimaryKey(alteredTableName, changeDescriptor.AlteredType.PhysicalKeyPropertyNames, isClusteredIndex)) )); } @@ -596,7 +597,10 @@ private void DropFields(string tableName, IEnumerable field - private void AppendFields(string tableName, IEnumerable addedFieldDescriptions, Dictionary defaultValues = null) + private void AppendFields(string tableName, + DataTypeChangeDescriptor changeDescriptor, + IEnumerable addedFieldDescriptions, + Dictionary defaultValues = null) { foreach (var addedFieldDescriptor in addedFieldDescriptions) { @@ -607,6 +611,34 @@ private void AppendFields(string tableName, IEnumerable add } CreateColumn(tableName, addedFieldDescriptor, defaultValue); + + // Updating VersionId field + if (addedFieldDescriptor.Name == nameof(IVersioned.VersionId) + && changeDescriptor.AlteredType.SuperInterfaces.Contains(typeof (IVersioned))) + { + string sourceField; + + if (changeDescriptor.AlteredType.DataTypeId == typeof (IPage).GetImmutableTypeId()) + { + sourceField = nameof(IPage.Id); + } + else + { + sourceField = changeDescriptor.AlteredType.Fields + .Where(f => f.InstanceType == typeof(Guid) + && (f.ForeignKeyReferenceTypeName?.Contains(typeof (IPage).FullName) ?? false)) + .OrderByDescending(f => f.Name == nameof(IPageData.PageId)) + .Select(f => f.Name) + .FirstOrDefault(); + } + + if (sourceField != null) + { + string updateVersionIdCommandText = + $"UPDATE [{tableName}] SET [{nameof(IVersioned.VersionId)}] = [{sourceField}]"; + ExecuteNonQuery(updateVersionIdCommandText); + } + } } } diff --git a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/Sql/SqlColumnInformation.cs b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/Sql/SqlColumnInformation.cs index 7bd09b43d0..db3973a480 100644 --- a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/Sql/SqlColumnInformation.cs +++ b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/Sql/SqlColumnInformation.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.ComponentModel; +using System.Linq; using Composite.Data.DynamicTypes; using Composite.Plugins.Data.DataProviders.MSSqlServerDataProvider.Foundation; @@ -15,7 +16,7 @@ public static SqlColumnInformation CreateSqlColumnInformation(this DataTypeDescr return new SqlColumnInformation( dataFieldDescriptor.Name, - dataTypeDescriptor.KeyPropertyNames.Contains(dataFieldDescriptor.Name), + dataTypeDescriptor.PhysicalKeyPropertyNames.Contains(dataFieldDescriptor.Name), false, false, dataFieldDescriptor.IsNullable, @@ -42,7 +43,7 @@ public sealed class SqlColumnInformation private readonly Type _type; private readonly SqlDbType _sqlDbType; - private int? _hasCode = null; + private int? _hashCode; internal SqlColumnInformation( string columnName, @@ -54,7 +55,7 @@ internal SqlColumnInformation( SqlDbType sqlDbType) { _columnName = columnName; - _trimmedColumnName = _columnName.Replace(" ", ""); + _trimmedColumnName = _columnName.Replace(" ", ""); _isPrimaryKey = isPrimaryKey; _isIdentity = isIdentity; _isComputed = isComputed; @@ -65,67 +66,43 @@ internal SqlColumnInformation( /// - public string ColumnName - { - get { return _columnName; } - } + public string ColumnName => _columnName; /// - public string TrimmedColumnName - { - get { return _trimmedColumnName; } - } + public string TrimmedColumnName => _trimmedColumnName; /// - public bool IsPrimaryKey - { - get { return _isPrimaryKey; } - } + public bool IsPrimaryKey => _isPrimaryKey; /// - public bool IsIdentity - { - get { return _isIdentity; } - } + public bool IsIdentity => _isIdentity; /// - public bool IsComputed - { - get { return _isComputed; } - } + public bool IsComputed => _isComputed; /// - public bool IsNullable - { - get { return _isNullable; } - } + public bool IsNullable => _isNullable; /// - public Type Type - { - get { return _type; } - } + public Type Type => _type; /// - public SqlDbType SqlDbType - { - get { return _sqlDbType; } - } + public SqlDbType SqlDbType => _sqlDbType; /// public override int GetHashCode() { - if (false == _hasCode.HasValue) + if (!_hashCode.HasValue) { - _hasCode = _columnName.GetHashCode() ^ + _hashCode = _columnName.GetHashCode() ^ _trimmedColumnName.GetHashCode() ^ _isPrimaryKey.GetHashCode() ^ _isIdentity.GetHashCode() ^ @@ -135,7 +112,7 @@ public override int GetHashCode() _sqlDbType.GetHashCode(); } - return _hasCode.Value; + return _hashCode.Value; } } } diff --git a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/SqlDataProvider_Stores.cs b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/SqlDataProvider_Stores.cs index 3798bb19cb..36019dd189 100644 --- a/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/SqlDataProvider_Stores.cs +++ b/Composite/Plugins/Data/DataProviders/MSSqlServerDataProvider/SqlDataProvider_Stores.cs @@ -508,11 +508,16 @@ private InterfaceGeneratedClassesInfo InitializeStoreTypes(InterfaceConfiguratio try { - interfaceType = dataTypes != null ? dataTypes[dataTypeId] : DataTypeTypesManager.GetDataType(dataTypeDescriptor); + if (dataTypes == null + || !dataTypes.TryGetValue(dataTypeId, out interfaceType) + || interfaceType == null) + { + interfaceType = DataTypeTypesManager.GetDataType(dataTypeDescriptor); + } if (interfaceType == null) { - Log.LogError(LogTitle, "The data interface type '{0}' does not exists and is not code generated. It will not be unusable", dataTypeDescriptor.TypeManagerTypeName); + Log.LogWarning(LogTitle, "The data interface type '{0}' does not exists and is not code generated. It will not be unusable", dataTypeDescriptor.TypeManagerTypeName); return result; } diff --git a/Composite/Plugins/Data/DataProviders/XmlDataProvider/CodeGeneration/DataIdClassGenerator.cs b/Composite/Plugins/Data/DataProviders/XmlDataProvider/CodeGeneration/DataIdClassGenerator.cs index 61ca1f7ed6..b117465885 100644 --- a/Composite/Plugins/Data/DataProviders/XmlDataProvider/CodeGeneration/DataIdClassGenerator.cs +++ b/Composite/Plugins/Data/DataProviders/XmlDataProvider/CodeGeneration/DataIdClassGenerator.cs @@ -58,7 +58,7 @@ public CodeTypeDeclaration CreateClass() AddGetHashCodeMethod(declaration); - foreach (DataFieldDescriptor field in _dataTypeDescriptor.KeyFields) + foreach (DataFieldDescriptor field in _dataTypeDescriptor.PhysicalKeyFields) { AddProperty(declaration, field.Name, field.InstanceType); } @@ -73,7 +73,7 @@ internal Dictionary Properties { get { - return _dataTypeDescriptor.KeyFields.ToDictionary(field => field.Name, field => field.InstanceType); + return _dataTypeDescriptor.PhysicalKeyFields.ToDictionary(field => field.Name, field => field.InstanceType); } } @@ -98,7 +98,7 @@ private void AddConstructor(CodeTypeDeclaration declaration) - foreach (var keyField in _dataTypeDescriptor.KeyFields) + foreach (var keyField in _dataTypeDescriptor.PhysicalKeyFields) { string propertyFieldName = MakePropertyFieldName(keyField.Name); string attributeVariableName = "attr" + keyField.Name; @@ -275,7 +275,8 @@ private void AddGetHashCodeMethod(CodeTypeDeclaration declaration) CodeExpression hashCodeExpression = null; - foreach (string keyPropertyName in _dataTypeDescriptor.KeyPropertyNames) +#warning We DO want IDataId classes to reflect both id and VersionId for data, right? + foreach (string keyPropertyName in _dataTypeDescriptor.PhysicalKeyFields.Select(f=>f.Name)) { string propertyFieldName = MakePropertyFieldName(_dataTypeDescriptor.Fields[keyPropertyName].Name); diff --git a/Composite/Plugins/Data/DataProviders/XmlDataProvider/CodeGeneration/XmlDataProviderCodeBuilder.cs b/Composite/Plugins/Data/DataProviders/XmlDataProvider/CodeGeneration/XmlDataProviderCodeBuilder.cs index 5ac12a9242..d3aad9b6c1 100644 --- a/Composite/Plugins/Data/DataProviders/XmlDataProvider/CodeGeneration/XmlDataProviderCodeBuilder.cs +++ b/Composite/Plugins/Data/DataProviders/XmlDataProvider/CodeGeneration/XmlDataProviderCodeBuilder.cs @@ -46,7 +46,7 @@ internal void AddDataType(DataTypeDescriptor dataTypeDescriptor) // Property serializer for entity tokens and more var keyPropertiesDictionary = new Dictionary(); var keyPropertiesList = new List>(); - foreach (var keyField in dataTypeDescriptor.KeyFields) + foreach (var keyField in dataTypeDescriptor.PhysicalKeyFields) { Verify.That(!keyPropertiesDictionary.ContainsKey(keyField.Name), "Key field with name '{0}' already present. Data type: {1}. Check for multiple [KeyPropertyName(...)] attributes.", keyField.Name, dataTypeDescriptor.Namespace + "." + dataTypeDescriptor.Name); diff --git a/Composite/Plugins/Data/DataProviders/XmlDataProvider/Foundation/InterfaceConfigurationManipulator.cs b/Composite/Plugins/Data/DataProviders/XmlDataProvider/Foundation/InterfaceConfigurationManipulator.cs index 400093a70e..05948e9b2f 100644 --- a/Composite/Plugins/Data/DataProviders/XmlDataProvider/Foundation/InterfaceConfigurationManipulator.cs +++ b/Composite/Plugins/Data/DataProviders/XmlDataProvider/Foundation/InterfaceConfigurationManipulator.cs @@ -247,7 +247,7 @@ private static XmlProviderInterfaceConfigurationElement BuildXmlProviderInterfac } configurationElement.ConfigurationDataIdProperties = new SimpleNameTypeConfigurationElementCollection(); - foreach (DataFieldDescriptor field in dataTypeDescriptor.KeyFields) + foreach (DataFieldDescriptor field in dataTypeDescriptor.PhysicalKeyFields) { configurationElement.ConfigurationDataIdProperties.Add(field.Name, field.InstanceType); } diff --git a/Composite/Plugins/Data/DataProviders/XmlDataProvider/Foundation/XmlDataProviderStoreManipulator.cs b/Composite/Plugins/Data/DataProviders/XmlDataProvider/Foundation/XmlDataProviderStoreManipulator.cs index c4a2771aa1..185f07a33f 100644 --- a/Composite/Plugins/Data/DataProviders/XmlDataProvider/Foundation/XmlDataProviderStoreManipulator.cs +++ b/Composite/Plugins/Data/DataProviders/XmlDataProvider/Foundation/XmlDataProviderStoreManipulator.cs @@ -11,6 +11,7 @@ using Composite.Data.DynamicTypes; using Composite.Data.Plugins.DataProvider; using Composite.Data.ProcessControlled.ProcessControllers.GenericPublishProcessController; +using Composite.Data.Types; namespace Composite.Plugins.Data.DataProviders.XmlDataProvider.Foundation @@ -62,8 +63,10 @@ public static void AlterStore(UpdateDataTypeDescriptor updateDescriptor, XmlProv var oldDataScopeConfigurationElement = fileForLanguage.Value; var newDataScopeConfigurationElement = newConfigurationElement.DataScopes[scopeIdentifier.Name][cultureName]; - newFieldValues = new Dictionary(); - newFieldValues.Add("PublicationStatus", GenericPublishProcessController.Published); + newFieldValues = new Dictionary + { + {"PublicationStatus", GenericPublishProcessController.Published} + }; CopyData(updateDescriptor.ProviderName, dataTypeChangeDescriptor, oldDataScopeConfigurationElement, newDataScopeConfigurationElement, newFieldValues); } @@ -77,8 +80,10 @@ public static void AlterStore(UpdateDataTypeDescriptor updateDescriptor, XmlProv var oldDataScopeConfigurationElement = fileByLanguage.Value; var newDataScopeConfigurationElement = newConfigurationElement.DataScopes[DataScopeIdentifier.AdministratedName][fileByLanguage.Key]; - newFieldValues = new Dictionary(); - newFieldValues.Add("PublicationStatus", GenericPublishProcessController.Published); + newFieldValues = new Dictionary + { + {"PublicationStatus", GenericPublishProcessController.Published} + }; CopyData(updateDescriptor.ProviderName, dataTypeChangeDescriptor, oldDataScopeConfigurationElement, newDataScopeConfigurationElement, newFieldValues, false); } @@ -122,8 +127,10 @@ public static void AlterStore(UpdateDataTypeDescriptor updateDescriptor, XmlProv { var newDataScopeConfigurationElement = newConfigurationElement.DataScopes[dataScopeIdentifier][locale.Name]; - var nfv = new Dictionary(newFieldValues); - nfv.Add("SourceCultureName", locale.Name); + var nfv = new Dictionary(newFieldValues) + { + {"SourceCultureName", locale.Name} + }; CopyData(updateDescriptor.ProviderName, dataTypeChangeDescriptor, oldDataScopeConfigurationElement, newDataScopeConfigurationElement, nfv, false); } @@ -178,6 +185,28 @@ private static void CopyData(string providerName, DataTypeChangeDescriptor dataT List newElements = new List(); + bool addingVersionId = dataTypeChangeDescriptor.AddedFields.Any(f => f.Name == nameof(IVersioned.VersionId)) + && dataTypeChangeDescriptor.AlteredType.SuperInterfaces.Any(s => s == typeof (IVersioned)); + + string versionIdSourceFieldName = null; + if (addingVersionId) + { + if (dataTypeChangeDescriptor.AlteredType.DataTypeId == typeof(IPage).GetImmutableTypeId()) + { + versionIdSourceFieldName = nameof(IPage.Id); + } + else + { + versionIdSourceFieldName = dataTypeChangeDescriptor.AlteredType.Fields + .Where(f => f.InstanceType == typeof(Guid) + && (f.ForeignKeyReferenceTypeName?.Contains(typeof(IPage).FullName) ?? false)) + .OrderByDescending(f => f.Name == nameof(IPageData.PageId)) + .Select(f => f.Name) + .FirstOrDefault(); + } + } + + foreach (XElement oldElement in oldDocument.Root.Elements()) { List newChildAttributes = new List(); @@ -222,25 +251,32 @@ private static void CopyData(string providerName, DataTypeChangeDescriptor dataT foreach (DataFieldDescriptor fieldDescriptor in dataTypeChangeDescriptor.AddedFields) { - if (fieldDescriptor.IsNullable == false - && !newChildAttributes.Any(attr => attr.Name == fieldDescriptor.Name)) + if (addingVersionId && fieldDescriptor.Name == nameof(IVersioned.VersionId) && versionIdSourceFieldName != null) { - XAttribute newChildAttribute = new XAttribute(fieldDescriptor.Name, GetDefaultValue(fieldDescriptor)); + var existingField = (Guid)oldElement.Attribute(versionIdSourceFieldName); + if (existingField != null) + { + newChildAttributes.Add(new XAttribute(fieldDescriptor.Name, existingField)); + continue; + } + } - if (newFieldValues.ContainsKey(fieldDescriptor.Name)) + if (!fieldDescriptor.IsNullable + && !newChildAttributes.Any(attr => attr.Name == fieldDescriptor.Name)) + { + object value; + if (!newFieldValues.TryGetValue(fieldDescriptor.Name, out value)) { - newChildAttribute.SetValue(newFieldValues[fieldDescriptor.Name]); + value = GetDefaultValue(fieldDescriptor); } - newChildAttributes.Add(newChildAttribute); + newChildAttributes.Add(new XAttribute(fieldDescriptor.Name, value)); } else if (newFieldValues.ContainsKey(fieldDescriptor.Name)) { XAttribute attribute = newChildAttributes.SingleOrDefault(attr => attr.Name == fieldDescriptor.Name); - if (attribute != null) - { - attribute.SetValue(newFieldValues[fieldDescriptor.Name]); - } + + attribute?.SetValue(newFieldValues[fieldDescriptor.Name]); } } diff --git a/Composite/Plugins/Data/DataProviders/XmlDataProvider/XmlDataProvider_Stores.cs b/Composite/Plugins/Data/DataProviders/XmlDataProvider/XmlDataProvider_Stores.cs index 76a88d7eef..f75d049159 100644 --- a/Composite/Plugins/Data/DataProviders/XmlDataProvider/XmlDataProvider_Stores.cs +++ b/Composite/Plugins/Data/DataProviders/XmlDataProvider/XmlDataProvider_Stores.cs @@ -146,10 +146,9 @@ private void InitializeExistingStores() try { - interfaceType = dataTypes[dataTypeDescriptor.DataTypeId]; - if (interfaceType == null) + if (!dataTypes.TryGetValue(dataTypeDescriptor.DataTypeId, out interfaceType) || interfaceType == null) { - Log.LogError(LogTitle, "The data interface type '{0}' does not exists and is not code generated. It will not be usable", dataTypeDescriptor.TypeManagerTypeName); + Log.LogWarning(LogTitle, "The data interface type '{0}' does not exists and is not code generated. It will not be usable", dataTypeDescriptor.TypeManagerTypeName); continue; } diff --git a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs index 13105a4f84..0d43b4bc1c 100644 --- a/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs +++ b/Composite/Plugins/Elements/ElementProviders/PageElementProvider/PageElementProvider.cs @@ -24,7 +24,7 @@ using Microsoft.Practices.EnterpriseLibrary.Common.Configuration; using Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder; using Microsoft.Practices.ObjectBuilder; -using Composite.C1Console.Security.Foundation; + namespace Composite.Plugins.Elements.ElementProviders.PageElementProvider { @@ -79,7 +79,7 @@ private static ResourceHandle GetIconHandle(string name) public PageElementProvider() { AuxiliarySecurityAncestorFacade.AddAuxiliaryAncestorProvider(this); - DataEvents.OnStoreChanged += new StoreEventHandler(DataEvents_IPageType_OnStoreChanged); + DataEvents.OnStoreChanged += DataEvents_IPageType_OnStoreChanged; } @@ -99,13 +99,7 @@ public ElementProviderContext Context - public bool ContainsLocalizedData - { - get - { - return true; - } - } + public bool ContainsLocalizedData => true; public IEnumerable GetRoots(SearchToken searchToken) @@ -316,23 +310,23 @@ public IEnumerable GetForeignChildren(EntityToken entityToken, SearchTo return _pageAssociatedHelper.GetChildren((DataGroupingProviderHelperEntityToken)entityToken, true); } - Dictionary pages; + IEnumerable pages; using (new DataScope(DataScopeIdentifier.Administrated)) { - pages = GetChildrenPages(entityToken, searchToken).ToDictionary(f => f.Id); + pages = GetChildrenPages(entityToken, searchToken).ToList(); } - Dictionary foreignAdministratedPages; + IEnumerable foreignAdministratedPages; using (new DataScope(DataScopeIdentifier.Administrated, UserSettings.ForeignLocaleCultureInfo)) { - foreignAdministratedPages = GetChildrenPages(entityToken, searchToken).ToDictionary(f => f.Id); + foreignAdministratedPages = GetChildrenPages(entityToken, searchToken).ToList(); } - Dictionary foreignPublicPages; + IEnumerable foreignPublicPages; using (new DataScope(DataScopeIdentifier.Public, UserSettings.ForeignLocaleCultureInfo)) { - foreignPublicPages = GetChildrenPages(entityToken, searchToken).ToList().ToDictionary(f => f.Id); + foreignPublicPages = GetChildrenPages(entityToken, searchToken).ToList(); } @@ -349,24 +343,31 @@ orderby ps.LocalOrdering var resultPages = new List>(); foreach (Guid pageId in childPageIds) { - IPage page; - if (pages.TryGetValue(pageId, out page)) + if (pages.Any(f => f.Id == pageId)) { - resultPages.Add(new KeyValuePair(PageLocaleState.Own, page)); + resultPages.AddRange( + pages.Where(f => f.Id == pageId) + .Select(p => new KeyValuePair(PageLocaleState.Own, p))); } - else if (foreignAdministratedPages.TryGetValue(pageId, out page) - && page.IsTranslatable()) + else if (foreignAdministratedPages.Any(f => f.Id == pageId && f.IsTranslatable())) { - resultPages.Add(new KeyValuePair(PageLocaleState.ForeignActive, page)); + resultPages.AddRange( + foreignAdministratedPages.Where(f => f.Id == pageId && f.IsTranslatable()) + .Select(p => new KeyValuePair(PageLocaleState.ForeignActive, p))); } - else if (foreignPublicPages.TryGetValue(pageId, out page)) + else if (foreignPublicPages.Any(f => f.Id == pageId)) { - resultPages.Add(new KeyValuePair(PageLocaleState.ForeignActive, page)); + resultPages.AddRange( + foreignPublicPages.Where(f => f.Id == pageId) + .Select(p => new KeyValuePair(PageLocaleState.ForeignActive, p))); } - else if (foreignAdministratedPages.TryGetValue(pageId, out page)) + else if (foreignAdministratedPages.Any(f => f.Id == pageId)) { - resultPages.Add(new KeyValuePair(PageLocaleState.ForeignDisabled, page)); + resultPages.AddRange( + foreignAdministratedPages.Where(f => f.Id == pageId) + .Select(p => new KeyValuePair(PageLocaleState.ForeignDisabled, p))); } + } List childPageElements = GetElements(resultPages, entityToken is PageElementProviderEntityToken); @@ -382,12 +383,12 @@ public Dictionary> GetParents(IEnumerable< foreach (EntityToken entityToken in entityTokens) { - DataEntityToken dataEntityToken = entityToken as DataEntityToken; - + var dataEntityToken = (DataEntityToken) entityToken; Type type = dataEntityToken.InterfaceType; + if (type != typeof(IPage)) continue; - Guid pageId = (Guid) dataEntityToken.DataSourceId.GetKeyValue(); + Guid pageId = (Guid) dataEntityToken.DataSourceId.GetKeyValue(nameof(IPage.Id)); Guid parentPageId = PageManager.GetParentId(pageId); if (parentPageId != Guid.Empty) continue; @@ -402,7 +403,7 @@ public Dictionary> GetParents(IEnumerable< private IEnumerable GetChildElements(EntityToken entityToken, IEnumerable childPageElements) { Guid? itemId = GetParentPageId(entityToken); - if (itemId.HasValue == false) return new Element[] { }; + if (!itemId.HasValue) return new Element[] { }; List associatedChildElements; if (itemId.Value != Guid.Empty) @@ -444,9 +445,7 @@ private IEnumerable GetChildElements(EntityToken entityToken, IEnumerab { IPage parentPage = ((DataEntityToken)entityToken).Data as IPage; - if (parentPage == null) return null; - - return parentPage.Id; + return parentPage?.Id; } throw new NotImplementedException(); @@ -463,7 +462,7 @@ private IEnumerable GetChildrenPages(EntityToken entityToken, SearchToken if (!searchToken.IsValidKeyword()) { - return PageServices.GetChildren(itemId.Value).Evaluate().AsQueryable(); + return OrderByVersions(PageServices.GetChildren(itemId.Value).Evaluate()); } string keyword = searchToken.Keyword.ToLowerInvariant(); @@ -496,7 +495,18 @@ from page in DataFacade.GetData() } } - return pages.AsQueryable(); + return OrderByVersions(pages); + } + + private IEnumerable OrderByVersions(IEnumerable pages) + { + return (from page in pages + group page by page.Id + into pageVersionGroups + let versions = pageVersionGroups.ToList() + let liveVersionName = versions.Count == 1 ? null : versions[0].GetLiveVersionName() + select pageVersionGroups.OrderByDescending(v => v.LocalizedVersionName() == liveVersionName).ToList()) + .SelectMany(v => v); } @@ -548,7 +558,7 @@ public bool OnElementDraggedAndDropped(EntityToken draggedEntityToken, EntityTok Guid oldParentId = draggedPage.GetParentId(); if (oldParentId != Guid.Empty) { - oldParent = DataFacade.GetData(f => f.Id == oldParentId).Single(); + oldParent = DataFacade.GetData(f => f.Id == oldParentId).FirstOrDefault(); } if (dragAndDropType == DragAndDropType.Move) @@ -571,7 +581,7 @@ public bool OnElementDraggedAndDropped(EntityToken draggedEntityToken, EntityTok break; } - urlTitle = string.Format("{0}{1}", draggedPage.UrlTitle, counter++); + urlTitle = $"{draggedPage.UrlTitle}{counter++}"; } draggedPage.UrlTitle = urlTitle; @@ -811,14 +821,15 @@ private List GetElements(List> pag private ElementVisualizedData MakeVisualData(IPage page, PageLocaleState pageLocaleState, string urlMappingName, bool isRootPage) { - bool hasChildren = PageServices.GetChildrenCount(page.Id) > 0 || _pageAssociatedHelper.HasChildren(page); var visualizedElement = new ElementVisualizedData { HasChildren = hasChildren, Label = (isRootPage || string.IsNullOrWhiteSpace(page.MenuTitle)) ? page.Title : page.MenuTitle, - ToolTip = page.Description + ToolTip = page.Description, + ElementBundle = page.Id.ToString(), + BundleElementName = page.LocalizedVersionName() }; if (pageLocaleState == PageLocaleState.Own) @@ -849,7 +860,7 @@ private ElementVisualizedData MakeVisualData(IPage page, PageLocaleState pageLoc visualizedElement.Icon = PageElementProvider.PageGhosted; visualizedElement.OpenedIcon = PageElementProvider.PageGhosted; visualizedElement.IsDisabled = false; - visualizedElement.Label = string.Format("{0} ({1})", visualizedElement.Label, urlMappingName); + visualizedElement.Label = $"{visualizedElement.Label} ({urlMappingName})"; } else { @@ -857,7 +868,7 @@ private ElementVisualizedData MakeVisualData(IPage page, PageLocaleState pageLoc visualizedElement.OpenedIcon = PageElementProvider.PageDisabled; visualizedElement.IsDisabled = true; visualizedElement.ToolTip = StringResourceSystemFacade.GetString("Composite.Plugins.PageElementProvider", "PageElementProvider.DisabledPage"); - visualizedElement.Label = string.Format("{0} ({1})", visualizedElement.Label, urlMappingName); + visualizedElement.Label = $"{visualizedElement.Label} ({urlMappingName})"; } return visualizedElement; @@ -897,10 +908,7 @@ internal sealed class DragAndDropActionToken : ActionToken { private static readonly PermissionType[] _permissionTypes = { PermissionType.Administrate, PermissionType.Edit }; - public override IEnumerable PermissionTypes - { - get { return _permissionTypes; } - } + public override IEnumerable PermissionTypes => _permissionTypes; } diff --git a/Composite/Plugins/Elements/UrlToEntityToken/DataUrlToEntityTokenMapper.cs b/Composite/Plugins/Elements/UrlToEntityToken/DataUrlToEntityTokenMapper.cs index 79d5eb77c4..d26119eb8a 100644 --- a/Composite/Plugins/Elements/UrlToEntityToken/DataUrlToEntityTokenMapper.cs +++ b/Composite/Plugins/Elements/UrlToEntityToken/DataUrlToEntityTokenMapper.cs @@ -57,7 +57,7 @@ public BrowserViewSettings TryGetBrowserViewSettings(EntityToken entityToken, bo if (data != null) { var key = data.GetUniqueKey(); - var publicData = DataFacade.TryGetDataByUniqueKey(dataEntityToken.InterfaceType, key); + var publicData = DataFacade.TryGetDataVersionsByUniqueKey(dataEntityToken.InterfaceType, key).FirstOrDefault(); if (publicData != null) { entityToken = publicData.GetDataEntityToken(); diff --git a/Composite/Plugins/Forms/WebChannel/UiContainerFactories/TemplatedUiContainer.cs b/Composite/Plugins/Forms/WebChannel/UiContainerFactories/TemplatedUiContainer.cs index 73a71eb734..cfe276f5f9 100644 --- a/Composite/Plugins/Forms/WebChannel/UiContainerFactories/TemplatedUiContainer.cs +++ b/Composite/Plugins/Forms/WebChannel/UiContainerFactories/TemplatedUiContainer.cs @@ -14,8 +14,8 @@ namespace Composite.Plugins.Forms.WebChannel.UiContainerFactories { internal class TemplatedUiContainer : IWebUiContainer { - private Type _templateUserControlType; - private string _templateFormVirtualPath; + private readonly Type _templateUserControlType; + private readonly string _templateFormVirtualPath; private TemplatedExecutionContainer _webDocument; internal TemplatedUiContainer(Type templateUserControlType, string templateFormVirtualPath) @@ -30,27 +30,30 @@ public IUiControl Render( IUiControl customToolbarItems, IFormChannelIdentifier channel, IDictionary eventHandlerBindings, - string containerLabel, - string containerLabelField, + string containerLabel, + string containerLabelField, + string containerTooltip, ResourceHandle containerIcon) { - if (string.IsNullOrEmpty(_templateFormVirtualPath) == false) + if (!string.IsNullOrEmpty(_templateFormVirtualPath)) { - WebEmbeddedFormUiControl document = new WebEmbeddedFormUiControl(channel); - document.FormPath = _templateFormVirtualPath; // "/Composite/Templates/Document.xml"; + var document = new WebEmbeddedFormUiControl(channel) + { + FormPath = _templateFormVirtualPath, + Bindings = new Dictionary(eventHandlerBindings) {{"Form", innerForm}} + }; + - document.Bindings = new Dictionary(eventHandlerBindings); - document.Bindings.Add("Form", innerForm); if (customToolbarItems != null) { document.Bindings.Add("CustomToolbarItems", customToolbarItems); } - _webDocument = new TemplatedExecutionContainer(document, _templateUserControlType, containerLabel, containerLabelField, containerIcon); + _webDocument = new TemplatedExecutionContainer(document, _templateUserControlType, containerLabel, containerLabelField, containerTooltip, containerIcon); } else { - _webDocument = new TemplatedExecutionContainer((IWebUiControl)innerForm, _templateUserControlType, containerLabel, containerLabelField, containerIcon); + _webDocument = new TemplatedExecutionContainer((IWebUiControl)innerForm, _templateUserControlType, containerLabel, containerLabelField, containerTooltip, containerIcon); } return _webDocument; @@ -72,6 +75,7 @@ internal class TemplatedExecutionContainer : UiControl, IWebUiControl readonly IWebUiControl _form; readonly Type _templateUserControlType; readonly string _containerLabel; + readonly string _containerTooltip; readonly string _containerLabelField; readonly ResourceHandle _containerIcon; @@ -79,12 +83,16 @@ internal class TemplatedExecutionContainer : UiControl, IWebUiControl TemplatedUiContainerBase _templateControl; - public TemplatedExecutionContainer(IWebUiControl form, Type templateUserControlType, string containerLabel, string containerLabelField, ResourceHandle containerIcon) + public TemplatedExecutionContainer( + IWebUiControl form, Type templateUserControlType, + string containerLabel, string containerLabelField, string containerTooltip, + ResourceHandle containerIcon) { _form = form; _templateUserControlType = templateUserControlType; _containerLabel = containerLabel; _containerLabelField = containerLabelField; + _containerTooltip = containerTooltip; _containerIcon = containerIcon; } @@ -109,6 +117,7 @@ public Control BuildWebControl() _messagePlaceHolder = _templateControl.GetMessagePlaceHolder(); _templateControl.SetContainerTitle(_containerLabel); _templateControl.SetContainerTitleField(_containerLabelField); + _templateControl.SetContainerTooltip(_containerTooltip); _templateControl.SetContainerIcon(_containerIcon); _templateControl.SetWebUiControlRef(_form); diff --git a/Composite/Plugins/Forms/WebChannel/UiContainerFactories/TemplatedUiContainerBase.cs b/Composite/Plugins/Forms/WebChannel/UiContainerFactories/TemplatedUiContainerBase.cs index 62aca196b5..7b181e99f6 100644 --- a/Composite/Plugins/Forms/WebChannel/UiContainerFactories/TemplatedUiContainerBase.cs +++ b/Composite/Plugins/Forms/WebChannel/UiContainerFactories/TemplatedUiContainerBase.cs @@ -7,7 +7,8 @@ using Composite.Core.ResourceSystem; using Composite.Core.WebClient.FlowMediators.FormFlowRendering; using Composite.Plugins.Forms.WebChannel.UiControlFactories; - +using System.Web.UI.HtmlControls; +using System.Linq; namespace Composite.Plugins.Forms.WebChannel.UiContainerFactories { @@ -29,6 +30,11 @@ public abstract class TemplatedUiContainerBase : UserControl /// public abstract void SetContainerTitle(string title); + /// + public virtual void SetContainerTooltip(string tooltip) + { + } + /// public void SetContainerTitleField(string titleField) { @@ -44,7 +50,7 @@ public string GetTitleFieldControlId() var mappings = new Dictionary(); - FormFlowUiDefinitionRenderer.ResolveBindingPathToCliendIDMappings(container, mappings); + FormFlowUiDefinitionRenderer.ResolveBindingPathToClientIDMappings(container, mappings); string clientId = mappings.ContainsKey(_titleField) ? mappings[_titleField] : ""; diff --git a/Composite/Plugins/Forms/WebChannel/UiControlFactories/TemplatedBoolSelectorUiControlFactory.cs b/Composite/Plugins/Forms/WebChannel/UiControlFactories/TemplatedBoolSelectorUiControlFactory.cs index 26375da70c..b911815e4b 100644 --- a/Composite/Plugins/Forms/WebChannel/UiControlFactories/TemplatedBoolSelectorUiControlFactory.cs +++ b/Composite/Plugins/Forms/WebChannel/UiControlFactories/TemplatedBoolSelectorUiControlFactory.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Specialized; using System.Configuration; using System.Web.UI; using Composite.C1Console.Forms; @@ -17,11 +18,8 @@ namespace Composite.Plugins.Forms.WebChannel.UiControlFactories /// /// [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] - public abstract class BoolSelectorTemplateUserControlBase : UserControl + public abstract class BoolSelectorTemplateUserControlBase : UserControl, IPostBackDataHandler { - private string _formControlLabel; - private bool _isTrue; - /// protected abstract void BindStateToProperties(); @@ -42,30 +40,42 @@ internal void InitializeWebViewState() } /// - public bool IsTrue - { - get { return _isTrue; } - set { _isTrue = value; } - } + public bool IsTrue { get; set; } /// - public string FormControlLabel - { - get { return _formControlLabel; } - set { _formControlLabel = value; } - } - + public string FormControlLabel { get; set; } /// public string TrueLabel { get; set; } /// public string FalseLabel { get; set; } + + /// + public EventHandler SelectionChangedEventHandler { get; set; } + + /// + /// When implemented by a class, processes postback data for an ASP.NET server control. + /// + /// + /// + /// + public virtual bool LoadPostData(string postDataKey, NameValueCollection postCollection) + { + return false; + } + + /// + /// When implemented by a class, signals the server control to notify the ASP.NET application that the state of the control has changed. + /// + public virtual void RaisePostDataChangedEvent() + { + } } internal sealed class TemplatedBoolSelectorUiControl : BoolSelectorUiControl, IWebUiControl { - private Type _userControlType; + private readonly Type _userControlType; private BoolSelectorTemplateUserControlBase _userControl; internal TemplatedBoolSelectorUiControl(Type userControlType) @@ -93,13 +103,14 @@ public Control BuildWebControl() _userControl.IsTrue = this.IsTrue; _userControl.TrueLabel = this.TrueLabel; _userControl.FalseLabel = this.FalseLabel; + _userControl.SelectionChangedEventHandler += this.SelectionChangedEventHandler; return _userControl; } - public bool IsFullWidthControl { get { return false; } } + public bool IsFullWidthControl => false; - public string ClientName { get { return _userControl.GetDataFieldClientName(); } } + public string ClientName => _userControl.GetDataFieldClientName(); } @@ -112,7 +123,7 @@ public TemplatedBoolSelectorUiControlFactory(TemplatedBoolSelectorUiControlFacto public override IUiControl CreateControl() { - TemplatedBoolSelectorUiControl control = new TemplatedBoolSelectorUiControl(this.UserControlType); + var control = new TemplatedBoolSelectorUiControl(this.UserControlType); return control; } diff --git a/Composite/Plugins/Forms/WebChannel/UiControlFactories/TemplatedDateTimeSelectorUiControlFactory.cs b/Composite/Plugins/Forms/WebChannel/UiControlFactories/TemplatedDateTimeSelectorUiControlFactory.cs index 50124a8fe5..595deb10ad 100644 --- a/Composite/Plugins/Forms/WebChannel/UiControlFactories/TemplatedDateTimeSelectorUiControlFactory.cs +++ b/Composite/Plugins/Forms/WebChannel/UiControlFactories/TemplatedDateTimeSelectorUiControlFactory.cs @@ -23,10 +23,10 @@ public abstract class DateTimeSelectorTemplateUserControlBase : UserControl private DateTime? _date; /// - protected abstract void BindStateToProperties(); + public abstract void BindStateToProperties(); /// - protected abstract void InitializeViewState(); + public abstract void InitializeViewState(); /// public abstract string GetDataFieldClientName(); @@ -76,6 +76,13 @@ public bool ShowHours set; } + /// + public bool Required + { + get; + set; + } + /// public string FormControlLabel { @@ -88,7 +95,7 @@ public string FormControlLabel internal sealed class TemplatedDateTimeSelectorUiControl : DateTimeSelectorUiControl, IWebUiControl, IValidatingUiControl { - private Type _userControlType; + private readonly Type _userControlType; private DateTimeSelectorTemplateUserControlBase _userControl; internal TemplatedDateTimeSelectorUiControl(Type userControlType) @@ -117,35 +124,30 @@ public Control BuildWebControl() _userControl.ReadOnly = this.ReadOnly; _userControl.ShowHours = this.ShowHours; _userControl.IsValid = true; + _userControl.Required = this.Required; return _userControl; } - public bool IsFullWidthControl { get { return false; } } + public bool IsFullWidthControl => false; - public string ClientName { get { return _userControl.GetDataFieldClientName(); } } + public string ClientName => _userControl.GetDataFieldClientName(); - public bool IsValid - { - get { return _userControl.IsValid; } - } + public bool IsValid => _userControl.IsValid; public bool ShowHours { get; set; } - public string ValidationError - { - get { return _userControl.ValidationError; } - } + public string ValidationError => _userControl.ValidationError; } [ConfigurationElementType(typeof(TemplatedDateTimeSelectorUiControlFactoryData))] internal sealed class TemplatedDateTimeSelectorUiControlFactory : Base.BaseTemplatedUiControlFactory { - private bool _showHours; + private readonly bool _showHours; public TemplatedDateTimeSelectorUiControlFactory(TemplatedDateTimeSelectorUiControlFactoryData data) : base(data) @@ -155,11 +157,10 @@ public TemplatedDateTimeSelectorUiControlFactory(TemplatedDateTimeSelectorUiCont public override IUiControl CreateControl() { - TemplatedDateTimeSelectorUiControl control = new TemplatedDateTimeSelectorUiControl(this.UserControlType); - - control.ShowHours = _showHours; - - return control; + return new TemplatedDateTimeSelectorUiControl(this.UserControlType) + { + ShowHours = _showHours + }; } } diff --git a/Composite/Plugins/Forms/WebChannel/UiControlFactories/TemplatedSelectorUiControlFactory.cs b/Composite/Plugins/Forms/WebChannel/UiControlFactories/TemplatedSelectorUiControlFactory.cs index 9c838b4ae1..7dcb4088c8 100644 --- a/Composite/Plugins/Forms/WebChannel/UiControlFactories/TemplatedSelectorUiControlFactory.cs +++ b/Composite/Plugins/Forms/WebChannel/UiControlFactories/TemplatedSelectorUiControlFactory.cs @@ -49,19 +49,20 @@ public KeyLabelPair(string key, string label) [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public abstract class SelectorTemplateUserControlBase : UserControl { - private Dictionary _selectorObjects = null; - private List _keyLabelPairList = null; - private List _selectedAsStrings = null; - private List _selectedObjects = null; - private EventHandler _changeEventHandler; + private Dictionary _selectorObjects; + private List _keyLabelPairList; + private List _selectedAsStrings; private const string _noneSelectionKey = "***C1.NONE***"; + private const string _noneSelectionLabel = ""; - /// - protected abstract void BindStateToProperties(); + /// + /// To be overridden in the controls + /// + public abstract void BindStateToProperties(); /// - protected abstract void InitializeViewState(); + public abstract void InitializeViewState(); /// @@ -74,8 +75,10 @@ public abstract class SelectorTemplateUserControlBase : UserControl /// public bool Required { get; set; } - /// - public bool MultiSelector { get; set; } + /// + /// When the selection is not required, the property will define if a "no selection" option should be added. + /// + public bool ProvideNoSelectionOption { get; set; } /// public bool CompactMode { get; set; } @@ -83,22 +86,24 @@ public abstract class SelectorTemplateUserControlBase : UserControl /// public bool ReadOnly { get; set; } + /// + public string OptionsKeyField { get; set; } + + /// + public string OptionsLabelField { get; set; } + + /// + public IEnumerable Options { get; set; } - internal string OptionsKeyField { get; set; } - internal string OptionsLabelField { get; set; } - internal IEnumerable Options { get; set; } internal SelectorBindingType BindingType { get; set; } /// - public EventHandler SelectedIndexChangedEventHandler - { - get { return _changeEventHandler; } - set { _changeEventHandler = value; } - } + public EventHandler SelectedIndexChangedEventHandler { get; set; } - internal void BindStateToControlProperties() + /// + public void BindStateToControlProperties() { InitializeSelectorElements(); @@ -132,9 +137,17 @@ internal void SetSelectedObjectsFromStringList(IEnumerable selectedAsStr if (bindToObject) { - foreach (string selectedAsString in selectedAsStrings.Where(_selectorObjects.ContainsKey)) + foreach (string selectedAsString in selectedAsStrings) { - this.SelectedObjects.Add(_selectorObjects[selectedAsString]); + if (_selectorObjects.ContainsKey(selectedAsString)) + { + this.SelectedObjects.Add(_selectorObjects[selectedAsString]); + } + else if(selectedAsString != _noneSelectionKey) + { + // ComboBox + this.SelectedObjects.Add(selectedAsString); + } } return; } @@ -143,27 +156,33 @@ internal void SetSelectedObjectsFromStringList(IEnumerable selectedAsStr { foreach (string selectedAsString in selectedAsStrings) { - if (selectedAsString != _noneSelectionKey) + if (selectedAsString == _noneSelectionKey) { - if (_selectorObjects.ContainsKey(selectedAsString)) - { - object key; + continue; + } - var @object = _selectorObjects[selectedAsString]; + if (!_selectorObjects.ContainsKey(selectedAsString)) + { + // ComboBox + SelectedObjects.Add(selectedAsString); + continue; + } - if (@object is XElement) - { - key = (@object as XElement).Attribute(this.OptionsKeyField).Value; - } - else - { - PropertyInfo keyPropertyInfo = @object.GetType().GetProperty(this.OptionsKeyField); - key = keyPropertyInfo.GetValue(@object, null); - } + object key; + + var @object = _selectorObjects[selectedAsString]; - this.SelectedObjects.Add(key); - } + if (@object is XElement) + { + key = (@object as XElement).Attribute(this.OptionsKeyField).Value; } + else + { + PropertyInfo keyPropertyInfo = @object.GetType().GetProperty(this.OptionsKeyField); + key = keyPropertyInfo.GetValue(@object, null); + } + + this.SelectedObjects.Add(key); } return; @@ -201,16 +220,19 @@ public IEnumerable SelectedKeys } else { - PropertyInfo keyPropertyInfo = this.SelectedObjects.First().GetType().GetProperty(this.OptionsKeyField); - if (keyPropertyInfo == null) throw new InvalidOperationException(string.Format("Malformed Selection configuration. The Selected binding type '{0}' does not have a property named '{1}'", this.SelectedObjects.First().GetType(), this.OptionsKeyField)); - + var objectType = this.SelectedObjects.First().GetType(); + PropertyInfo keyPropertyInfo = objectType.GetProperty(this.OptionsKeyField); + if (keyPropertyInfo == null) { + throw new InvalidOperationException($"Malformed Selection configuration. The Selected binding type '{objectType}' does not have a property named '{this.OptionsKeyField}'"); + } + foreach (object selectedObject in this.SelectedObjects) { string selectedObjectKey = keyPropertyInfo.GetValue(selectedObject, null).ToString(); if (_selectorObjects.ContainsKey(selectedObjectKey)) { - _selectedAsStrings.Add(selectedObject.ToString()); + _selectedAsStrings.Add(selectedObjectKey); } } } @@ -239,18 +261,8 @@ public IEnumerable SelectedKeys } - - internal List SelectedObjects - { - get - { - return _selectedObjects; - } - set - { - _selectedObjects = value; - } - } + /// + public List SelectedObjects { get; set; } /// @@ -271,13 +283,18 @@ private void InitializeSelectorElements() Verify.That(OptionsKeyField != "" && OptionsKeyField != ".", "Key attribute name is not defined"); Verify.That(OptionsLabelField != "" && OptionsLabelField != ".", "Label attribute name is not defined"); } + else + { + Verify.IsNotNull(OptionsKeyField, $"{nameof(OptionsKeyField)} is null"); + Verify.IsNotNull(OptionsLabelField, $"{nameof(OptionsLabelField)} is null"); + } _selectorObjects = new Dictionary(); _keyLabelPairList = new List(); - if (!Required && !MultiSelector) + if (!Required && ProvideNoSelectionOption) { - _keyLabelPairList.Add(new KeyLabelPair(_noneSelectionKey, "")); + _keyLabelPairList.Add(new KeyLabelPair(_noneSelectionKey, _noneSelectionLabel)); } PropertyInfo keyPropertyInfo = null; @@ -410,20 +427,20 @@ public Control BuildWebControl() _userControl.BindingType = this.BindingType; _userControl.Required = this.Required; _userControl.ReadOnly = this.ReadOnly; - _userControl.MultiSelector = false; + _userControl.ProvideNoSelectionOption = true; return _userControl; } - public bool IsFullWidthControl { get { return false; } } + public bool IsFullWidthControl => false; - public string ClientName { get { return _userControl.GetDataFieldClientName(); } } + public string ClientName => _userControl.GetDataFieldClientName(); } internal sealed class TemplatedMultiSelectorUiControl : MultiSelectorUiControl, IWebUiControl { - private Type _userControlType; + private readonly Type _userControlType; private SelectorTemplateUserControlBase _userControl; @@ -471,14 +488,13 @@ public Control BuildWebControl() _userControl.OptionsKeyField = this.OptionsKeyField; _userControl.BindingType = this.BindingType; _userControl.Required = this.Required; - _userControl.MultiSelector = true; _userControl.CompactMode = this.CompactMode; _userControl.SelectedObjects = new List(); if (this.Selected != null) { - if (string.IsNullOrEmpty(this.SelectedAsString) == false) + if (!string.IsNullOrEmpty(this.SelectedAsString)) { throw new InvalidOperationException("Binding properties 'Selected' and 'SelectedAsString' can not be set at the same time."); } @@ -490,7 +506,7 @@ public Control BuildWebControl() } else { - if (string.IsNullOrEmpty(this.SelectedAsString) == false) + if (!string.IsNullOrEmpty(this.SelectedAsString)) { _userControl.SetSelectedObjectsFromStringList(this.SelectedAsString.Split(',')); } @@ -499,9 +515,9 @@ public Control BuildWebControl() return _userControl; } - public bool IsFullWidthControl { get { return false; } } + public bool IsFullWidthControl => false; - public string ClientName { get { return _userControl.GetDataFieldClientName(); } } + public string ClientName => _userControl.GetDataFieldClientName(); } @@ -519,7 +535,7 @@ public TemplatedSelectorUiControlFactory(TemplatedSelectorUiControlFactoryData d public override IUiControl CreateControl() { - if (_data.MultiSelector == false) + if (!_data.MultiSelector) { TemplatedSelectorUiControl control = new TemplatedSelectorUiControl(this.UserControlType); control.BindingType = _data.BindingType; diff --git a/Composite/Plugins/Functions/FunctionProviders/RazorFunctionProvider/RazorBasedFunction.cs b/Composite/Plugins/Functions/FunctionProviders/RazorFunctionProvider/RazorBasedFunction.cs index be5d072bc9..8501dacbdb 100644 --- a/Composite/Plugins/Functions/FunctionProviders/RazorFunctionProvider/RazorBasedFunction.cs +++ b/Composite/Plugins/Functions/FunctionProviders/RazorFunctionProvider/RazorBasedFunction.cs @@ -4,7 +4,6 @@ using System.Threading; using System.Web.WebPages; using Composite.AspNet.Razor; -using Composite.Core.Extensions; using Composite.Core.IO; using Composite.Core.WebClient; using Composite.Core.Xml; @@ -28,19 +27,26 @@ public RazorBasedFunction(string ns, string name, string description, Type retur protected override void InitializeParameters() { - WebPageBase razorPage; + WebPageBase razorPage = null; - using (BuildManagerHelper.DisableUrlMetadataCachingScope()) + try { - razorPage = WebPage.CreateInstanceFromVirtualPath(VirtualPath); - } + using (BuildManagerHelper.DisableUrlMetadataCachingScope()) + { + razorPage = WebPage.CreateInstanceFromVirtualPath(VirtualPath); + } - if (!(razorPage is RazorFunction)) + if (!(razorPage is RazorFunction)) + { + throw new InvalidOperationException($"Failed to initialize function from cache. Path: '{VirtualPath}'"); + } + + Parameters = FunctionBasedFunctionProviderHelper.GetParameters(razorPage as RazorFunction, typeof (RazorFunction), VirtualPath); + } + finally { - throw new InvalidOperationException("Failed to initialize function from cache. Path: '{0}'".FormatWith(VirtualPath)); + (razorPage as IDisposable)?.Dispose(); } - - Parameters = FunctionBasedFunctionProviderHelper.GetParameters(razorPage as RazorFunction, typeof(RazorFunction), VirtualPath); } public override object Execute(ParameterList parameters, FunctionContextContainer context) diff --git a/Composite/Plugins/Functions/FunctionProviders/StandardFunctionProvider/IDataGenerated/GetXml.cs b/Composite/Plugins/Functions/FunctionProviders/StandardFunctionProvider/IDataGenerated/GetXml.cs index caf254ac3a..1dc54edfe2 100644 --- a/Composite/Plugins/Functions/FunctionProviders/StandardFunctionProvider/IDataGenerated/GetXml.cs +++ b/Composite/Plugins/Functions/FunctionProviders/StandardFunctionProvider/IDataGenerated/GetXml.cs @@ -757,7 +757,7 @@ private static IReferencedDataHelper BuildImpl(string foreignKeyProperty Type destinationType = keyInfo.TargetType; PropertyInfo sourceKeyPropertyInfo = sourceType.GetDataPropertyRecursivly(foreignKeyPropertyName); - PropertyInfo destinationKeyPropertyInfo = destinationType.GetKeyProperties().Single(); + PropertyInfo destinationKeyPropertyInfo = destinationType.GetSingleKeyProperty(); Type keyFieldType = destinationKeyPropertyInfo.PropertyType; Type[] genericArgs = new Type[] { typeof(SOURCE), destinationType, keyFieldType }; diff --git a/Composite/Plugins/Routing/InternalUrlConverters/DataInternalUrlConverter.cs b/Composite/Plugins/Routing/InternalUrlConverters/DataInternalUrlConverter.cs index 22e0205d4b..bf363e0498 100644 --- a/Composite/Plugins/Routing/InternalUrlConverters/DataInternalUrlConverter.cs +++ b/Composite/Plugins/Routing/InternalUrlConverters/DataInternalUrlConverter.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Reflection; using Composite.Core.Routing; using Composite.Core.Types; @@ -10,7 +9,6 @@ namespace Composite.Plugins.Routing.InternalUrlConverters { class DataInternalUrlConverter: IInternalUrlConverter { - private readonly IEnumerable _urlPrefixes; private readonly Type _type; private readonly Type _keyType; private readonly ConstructorInfo _dataReferenceConstructor; @@ -18,18 +16,15 @@ class DataInternalUrlConverter: IInternalUrlConverter public DataInternalUrlConverter(string shortTypeName, Type type) { - _urlPrefixes = new[] { shortTypeName + "(" }; + AcceptedUrlPrefixes = new[] { shortTypeName + "(" }; _type = type; - _keyType = _type.GetKeyProperties().Single().PropertyType; + _keyType = _type.GetSingleKeyProperty().PropertyType; _dataReferenceConstructor = typeof(DataReference<>).MakeGenericType(_type).GetConstructor(new[] { typeof(object) }); } - public IEnumerable AcceptedUrlPrefixes - { - get { return _urlPrefixes; } - } + public IEnumerable AcceptedUrlPrefixes { get; } public string ToPublicUrl(string internalDataUrl, UrlSpace urlSpace) diff --git a/Composite/Plugins/Routing/Pages/DefaultPageUrlProvider.cs b/Composite/Plugins/Routing/Pages/DefaultPageUrlProvider.cs index 24a6243169..08542242d1 100644 --- a/Composite/Plugins/Routing/Pages/DefaultPageUrlProvider.cs +++ b/Composite/Plugins/Routing/Pages/DefaultPageUrlProvider.cs @@ -462,18 +462,22 @@ private PageUrlData ParsePagePath(string pagePath, PublicationScope publicationS if (canBePublicUrl) { - Guid? pageId = TryGetPageByUrlTitlePath(pagePath, pathInfoExctracted, hostnameBinding, ref pathInfo); + IPage page = TryGetPageByUrlTitlePath(pagePath, pathInfoExctracted, hostnameBinding, ref pathInfo); - if (pageId != null && pageId != Guid.Empty) + if (page != null) { - return new PageUrlData(pageId.Value, publicationScope, locale) { PathInfo = pathInfo}; + return new PageUrlData(page.Id, publicationScope, locale) + { + VersionId = page.VersionId, + PathInfo = pathInfo + }; } } return null; } - private static Guid? TryGetPageByUrlTitlePath(string pagePath, bool pathInfoExtracted, IHostnameBinding hostnameBinding, ref string pathInfo) + private static IPage TryGetPageByUrlTitlePath(string pagePath, bool pathInfoExtracted, IHostnameBinding hostnameBinding, ref string pathInfo) { string[] pageUrlTitles = pagePath.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries); @@ -481,12 +485,11 @@ private PageUrlData ParsePagePath(string pagePath, PublicationScope publicationS { if (hostnameBinding != null) { - if (!hostnameBinding.IncludeHomePageInUrl) return hostnameBinding.HomePageId; - - IPage rootPage = PageManager.GetPageById(hostnameBinding.HomePageId); - if (rootPage != null && string.IsNullOrEmpty(rootPage.UrlTitle)) + IPage rootPage = PageManager.GetPageById(hostnameBinding.HomePageId, true); + if (rootPage != null && + (!hostnameBinding.IncludeHomePageInUrl || string.IsNullOrEmpty(rootPage.UrlTitle))) { - return hostnameBinding.HomePageId; + return rootPage; } return null; @@ -496,69 +499,69 @@ private PageUrlData ParsePagePath(string pagePath, PublicationScope publicationS IEnumerable rootPages = GetChildPages(Guid.Empty); if (pageUrlTitles.Length == 0) { - return rootPages.Where(p => string.IsNullOrEmpty(p.UrlTitle)).Select(p => p.Id).FirstOrDefault(); + return rootPages.FirstOrDefault(p => string.IsNullOrEmpty(p.UrlTitle)); } string firstUrlTitle = pageUrlTitles[0]; - Guid? firstPageId = null; + IPage firstPage = null; if (hostnameBinding != null) { - IPage rootPage = PageManager.GetPageById(hostnameBinding.HomePageId); + IPage rootPage = PageManager.GetPageById(hostnameBinding.HomePageId, true); bool rootPageIsOmmited = rootPage != null && !hostnameBinding.IncludeHomePageInUrl || string.IsNullOrEmpty(rootPage.UrlTitle); if (rootPageIsOmmited) { - firstPageId = FindMatchingPage(rootPage.Id, firstUrlTitle); + firstPage = FindMatchingPage(rootPage.Id, firstUrlTitle); } } - if (firstPageId == null) + if (firstPage == null) { IPage defaultRootPage = rootPages.FirstOrDefault(p => string.IsNullOrEmpty(p.UrlTitle)); if (defaultRootPage != null) { - firstPageId = FindMatchingPage(defaultRootPage.Id, firstUrlTitle); + firstPage = FindMatchingPage(defaultRootPage.Id, firstUrlTitle); } - if (firstPageId == null) + if (firstPage == null) { // Searching the first pageId among root pages - firstPageId = FindMatchingPage(Guid.Empty, firstUrlTitle); + firstPage = FindMatchingPage(Guid.Empty, firstUrlTitle); } - if (firstPageId == null) return null; + if (firstPage == null) return null; } - Guid currentPageId = firstPageId.Value; + IPage currentPage = firstPage; - if (pageUrlTitles.Length == 1) return currentPageId; + if (pageUrlTitles.Length == 1) return currentPage; for (int i = 1; i < pageUrlTitles.Length; i++) { - Guid? nextPage = FindMatchingPage(currentPageId, pageUrlTitles[i]); + IPage nextPage = FindMatchingPage(currentPage.Id, pageUrlTitles[i]); if (nextPage == null) { if (pathInfoExtracted) return null; pathInfo = "/" + string.Join("/", pageUrlTitles.Skip(i)); - return currentPageId; + return currentPage; } - currentPageId = nextPage.Value; + currentPage = nextPage; } - return currentPageId; + return currentPage; } - private static Guid? FindMatchingPage(Guid parentId, string urlTitle) + private static IPage FindMatchingPage(Guid parentId, string urlTitle) { foreach (var page in GetChildPages(parentId)) { if(string.Equals(page.UrlTitle, urlTitle, StringComparison.OrdinalIgnoreCase)) { - return page.Id; + return page; } } @@ -571,7 +574,7 @@ private static IEnumerable GetChildPages(Guid parentId) for (int i=0; i() .Where(d => d.UserGroupId == userGroupId) .ToList() - .Where(d => userGroupPermissionDefinition.EntityToken.Equals(DeserializeSilent(d.SerializedEntityToken))) + .Where(d => userGroupPermissionDefinition.EntityToken.EqualsWithVersionIgnore(DeserializeSilent(d.SerializedEntityToken))) .ToList(); DataFacade.Delete(existingPermissionDefinitions); @@ -135,7 +135,7 @@ public void RemoveUserGroupPermissionDefinition(Guid userGroupId, string seriali toDelete = DataFacade.GetData() .Where(ugpd => ugpd.UserGroupId == userGroupId) .ToList() - .Where(d => entityToken.Equals(DeserializeSilent(d.SerializedEntityToken))) + .Where(d => entityToken.EqualsWithVersionIgnore(DeserializeSilent(d.SerializedEntityToken))) .ToList(); } else diff --git a/Composite/Plugins/Security/UserPermissionDefinitionProvider/DataBaseUserPermissionDefinitionProvider/DataBaseUserPermissionDefinitionProvider.cs b/Composite/Plugins/Security/UserPermissionDefinitionProvider/DataBaseUserPermissionDefinitionProvider/DataBaseUserPermissionDefinitionProvider.cs index 5afa693da2..ed25a29945 100644 --- a/Composite/Plugins/Security/UserPermissionDefinitionProvider/DataBaseUserPermissionDefinitionProvider/DataBaseUserPermissionDefinitionProvider.cs +++ b/Composite/Plugins/Security/UserPermissionDefinitionProvider/DataBaseUserPermissionDefinitionProvider/DataBaseUserPermissionDefinitionProvider.cs @@ -87,7 +87,7 @@ public void SetUserPermissionDefinition(UserPermissionDefinition userPermissionD DataFacade.GetData() .Where(d => d.Username == username) .ToList() - .Where(d => userPermissionDefinition.EntityToken.Equals(DeserializeSilent(d.SerializedEntityToken))) + .Where(d => userPermissionDefinition.EntityToken.EqualsWithVersionIgnore(DeserializeSilent(d.SerializedEntityToken))) .ToList(); DataFacade.Delete(existingUserPermissionDefinitions); @@ -130,7 +130,7 @@ public void RemoveUserPermissionDefinition(UserToken userToken, string serialize toDelete = DataFacade.GetData() .Where(upd => upd.Username == username) .ToList() - .Where(d => entityToken.Equals(DeserializeSilent(d.SerializedEntityToken))) + .Where(d => entityToken.EqualsWithVersionIgnore(DeserializeSilent(d.SerializedEntityToken))) .ToList(); } else diff --git a/Composite/Properties/AssemblyInfo.cs b/Composite/Properties/AssemblyInfo.cs index c9d5f3b96b..8bfac26e19 100644 --- a/Composite/Properties/AssemblyInfo.cs +++ b/Composite/Properties/AssemblyInfo.cs @@ -8,9 +8,9 @@ // associated with an assembly. #if !InternalBuild -[assembly: AssemblyTitle("Composite C1 5.1")] +[assembly: AssemblyTitle("Composite C1 5.2")] #else -[assembly: AssemblyTitle("Composite C1 5.1 (Internal Build)")] +[assembly: AssemblyTitle("Composite C1 5.2 (Internal Build)")] #endif [assembly: AssemblyDescription("Composite C1 Core classes")] @@ -39,7 +39,7 @@ // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("5.1.*")] +[assembly: AssemblyVersion("5.2.*")] [assembly: InternalsVisibleTo("UpgradePackage")] [assembly: InternalsVisibleTo("Composite.Workflows")] \ No newline at end of file diff --git a/Composite/RuntimeInformation.cs b/Composite/RuntimeInformation.cs index 0c714a4317..955734de88 100644 --- a/Composite/RuntimeInformation.cs +++ b/Composite/RuntimeInformation.cs @@ -64,9 +64,19 @@ private static bool IsUnittestImpl { get { - string applicationName = AppDomain.CurrentDomain.SetupInformation.ApplicationName; + var domain = AppDomain.CurrentDomain; + string applicationName = domain.SetupInformation.ApplicationName; - return applicationName == null || applicationName == "vstesthost.exe"; + return domain.FriendlyName.StartsWith("NUnit ") + || applicationName == null || applicationName == "vstesthost.exe"; + } + } + + internal static bool IsTestEnvironment + { + get + { + return true; } } diff --git a/CompositeC1.sln b/CompositeC1.sln index 6c6b61cccc..146a7c7dd2 100644 --- a/CompositeC1.sln +++ b/CompositeC1.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 +VisualStudioVersion = 14.0.25123.0 MinimumVisualStudioVersion = 14.0.0.0 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{44113BBC-CB18-41CF-AB26-6D190BA4E117}" EndProject diff --git a/Website/Composite/CompileScripts.xml b/Website/Composite/CompileScripts.xml index f980570ce8..771dcf497b 100644 --- a/Website/Composite/CompileScripts.xml +++ b/Website/Composite/CompileScripts.xml @@ -216,6 +216,7 @@ - - - + > + + diff --git a/Website/Composite/controls/FormsControls/FormUiControlTemplates/DateTimeSelectors/DateSelector.ascx b/Website/Composite/controls/FormsControls/FormUiControlTemplates/DateTimeSelectors/DateSelector.ascx index 99dc370402..2260076633 100644 --- a/Website/Composite/controls/FormsControls/FormUiControlTemplates/DateTimeSelectors/DateSelector.ascx +++ b/Website/Composite/controls/FormsControls/FormUiControlTemplates/DateTimeSelectors/DateSelector.ascx @@ -3,7 +3,9 @@
+ image="${icon:calendar-full}" value="<%= this.CurrentStringValue %>" + readonly="<%=this.ReadOnly.ToString().ToLower()%>" + required="<%=this.Required.ToString().ToLower()%>" />
@@ -21,4 +23,4 @@ runat="server">forward
-
+ \ No newline at end of file diff --git a/Website/Composite/controls/FormsControls/FormUiControlTemplates/DateTimeSelectors/DateSelector.ascx.cs b/Website/Composite/controls/FormsControls/FormUiControlTemplates/DateTimeSelectors/DateSelector.ascx.cs index 6f20a4b2c0..4652ddad2b 100644 --- a/Website/Composite/controls/FormsControls/FormUiControlTemplates/DateTimeSelectors/DateSelector.ascx.cs +++ b/Website/Composite/controls/FormsControls/FormUiControlTemplates/DateTimeSelectors/DateSelector.ascx.cs @@ -7,6 +7,8 @@ using System.Web.UI; using System.Linq; using Composite.Core.Configuration; +using Composite.Core.Extensions; + namespace Composite.controls.FormsControls.FormUiControlTemplates.DateTimeSelectors { @@ -23,12 +25,6 @@ private string ResetOnClickValue public PlaceHolder MessagesPlaceHolder; public string CurrentStringValue; - private static string TimeZoneAbbriviatedName() - { - return StringResourceSystemFacade.GetString("Composite.Plugins.TimezoneAbbriviations", - "TimezoneAbbriviations." + GlobalSettingsFacade.TimeZone.Id); - } - protected void Page_Init(object sender, EventArgs e) { if (ReadOnly) @@ -46,16 +42,13 @@ private void InsertSelectedDate(DateTime? toShow) { if (toShow.HasValue && toShow.Value != DateTime.MinValue) { - DateTime convertedToShow = TimeZoneInfo.ConvertTime(toShow.Value, GlobalSettingsFacade.TimeZone); - if (!ShowHours) { - this.CurrentStringValue = convertedToShow.ToShortDateString(); + this.CurrentStringValue = toShow.Value.ToTimeZoneDateString(); } else { - this.CurrentStringValue = string.Format("{0} {1} {2}", convertedToShow.ToShortDateString(), - convertedToShow.ToShortTimeString(), TimeZoneAbbriviatedName()); + this.CurrentStringValue = toShow.Value.ToTimeZoneDateTimeString(); } } else @@ -64,7 +57,7 @@ private void InsertSelectedDate(DateTime? toShow) } } - protected override void BindStateToProperties() + public override void BindStateToProperties() { if (this.ReadOnly) return; @@ -77,14 +70,16 @@ protected override void BindStateToProperties() } else { - string stringValueWithoutTimezone = this.CurrentStringValue.Replace(TimeZoneAbbriviatedName(),""); - - DateTime parsedTime = DateTime.Parse(stringValueWithoutTimezone); + DateTime parsedTime; + if (!DateTimeExtensionMethods.TryParseInTimeZone(this.CurrentStringValue, out parsedTime)) + { + throw new FormatException(); + } if (!ShowHours) parsedTime -= parsedTime.TimeOfDay; - this.Date = TimeZoneInfo.ConvertTime(parsedTime, GlobalSettingsFacade.TimeZone,TimeZoneInfo.Utc).ToLocalTime(); + this.Date = parsedTime.FromTimeZoneToUtc().ToLocalTime(); } this.IsValid = true; } @@ -98,20 +93,20 @@ protected override void BindStateToProperties() private string SampleDateString { - get - { + get + { if(ShowHours) { - return string.Format("{0} {1} {2}", DateTime.Now.ToShortDateString(), DateTime.Now.ToShortTimeString(),TimeZoneAbbriviatedName()); + return DateTime.Now.ToTimeZoneDateTimeString(); } else { - return DateTime.Now.ToShortDateString(); - } + return DateTime.Now.ToTimeZoneDateString(); + } } } - protected override void InitializeViewState() + public override void InitializeViewState() { SetCalendar(this.Date); InsertSelectedDate(this.Date); @@ -159,11 +154,11 @@ public void CalendarSelectionChange(object sender, EventArgs e) if (ShowHours) { DateTime oldDateTime; - if (DateTime.TryParse(this.CurrentStringValue.Replace(TimeZoneAbbriviatedName(), ""), out oldDateTime)) + if (DateTimeExtensionMethods.TryParseInTimeZone(this.CurrentStringValue, out oldDateTime)) toShow += oldDateTime.TimeOfDay; } - InsertSelectedDate(TimeZoneInfo.ConvertTime(toShow, GlobalSettingsFacade.TimeZone, TimeZoneInfo.Utc)); + InsertSelectedDate(toShow.FromTimeZoneToUtc()); this.MessagesPlaceHolder.Controls.Add(new DocumentDirtyEvent()); } diff --git a/Website/Composite/controls/FormsControls/FormUiControlTemplates/Selectors/ComboBox.ascx b/Website/Composite/controls/FormsControls/FormUiControlTemplates/Selectors/ComboBox.ascx index 4105f983c7..dcc77560c5 100644 --- a/Website/Composite/controls/FormsControls/FormUiControlTemplates/Selectors/ComboBox.ascx +++ b/Website/Composite/controls/FormsControls/FormUiControlTemplates/Selectors/ComboBox.ascx @@ -1,9 +1,11 @@ <%@ Control Language="C#" Inherits="Composite.Plugins.Forms.WebChannel.UiControlFactories.SelectorTemplateUserControlBase" %> <%@ Import Namespace="System.Linq" %> +<%@ Import Namespace="System.Security.Policy" %> +<%@ Import Namespace="Composite.Core.WebClient.UiControlLib.Foundation" %>