From 9e3614007745521d32f00aff9653ff701700f48d Mon Sep 17 00:00:00 2001 From: Granfeldt_cp Date: Wed, 16 Dec 2015 04:20:36 -0800 Subject: [PATCH] Added ClearSingleValeAttribute. Moving to Tracer for logging --- ..svnbridge/Granfeldt.FIM.ActivityLibrary.v11.suo | 1 + ..svnbridge/Granfeldt.FIM.ActivityLibrary.v12.suo | 1 + .../v14/..svnbridge/.suo | 1 + .vs/Granfeldt.FIM.ActivityLibrary/v14/.suo | Bin 0 -> 205312 bytes Granfeldt.FIM.ActivityLibrary.v11.suo | Bin 0 -> 191488 bytes Granfeldt.FIM.ActivityLibrary.v12.suo | Bin 0 -> 219648 bytes .../BackReferenceUpdateMemberActivity.cs | 197 ++++++++++++ .../BackReferenceUpdateMemberActivity.designer.cs | 206 +++++++++++++ .../BackReferenceUpdateMemberActivity.rules | 32 ++ .../BackReferenceUpdateMemberSettingsPart.cs | 197 ++++++++++++ .../GetReferenceValuesFromObjectActivity.cs | 147 +++++++++ ...etReferenceValuesFromObjectActivity.designer.cs | 75 +++++ ...UpdatesToReferenceAttributeActivity.Designer.cs | 48 +++ .../GetUpdatesToReferenceAttributeActivity.cs | 289 ++++++++++++++++++ .../UpdateReferenceAttributeActivity.Designer.cs | 90 ++++++ .../UpdateReferenceAttributeActivity.cs | 133 ++++++++ .../UpdateReferenceAttributesAsNeededActivity.cs | 141 +++++++++ ...ReferenceAttributesAsNeededActivity.designer.cs | 102 +++++++ .../Activity.AddRemoveFromMultiValue.Designer.cs | 204 +++++++++++++ ...ctivity.AddRemoveFromMultiValue.SettingsPart.cs | 121 ++++++++ .../Activity.AddRemoveFromMultiValue.cs | 230 ++++++++++++++ ...Activity.ClearSingleValuedAttribute.Designer.cs | 133 ++++++++ .../Activity.ClearSingleValuedAttribute.cs | 180 +++++++++++ ...earSingleValuedAttributeActivitySettingsPart.cs | 182 +++++++++++ .../Activity.CodeRun/Activity.CodeRun.cs | 44 +-- .../Base.ActivitySettings/Base.ActivitySettings.cs | 86 ++++-- .../Base.AttributeValue/Base.AttributeValue.cs | 340 ++++++++++----------- .../Base/Base.Common/Base.Common.cs | 1 - ...AddRemoveMultiValueAsNeededActivity.Designer.cs | 119 ++++++++ .../Helper.AddRemoveMultiValueAsNeededActivity.cs | 221 ++++++++++++++ ...tomer.ReconcileSoftwareGroupMembers.Designer.cs | 152 +++++++++ ...r.ReconcileSoftwareGroupMembers.SettingsPart.cs | 92 ++++++ .../Customer.ReconcileSoftwareGroupMembers.cs | 219 +++++++++++++ ...UpdateReferenceOnRegExMatchActivity.Designer.cs | 164 ++++++++++ ...teReferenceOnRegExMatchActivity.SettingsPart.cs | 126 ++++++++ .../UpdateReferenceOnRegExMatchActivity.cs | 259 ++++++++++++++++ .../Granfeldt.FIM.ActivityLibrary.csproj | 33 +- .../Install-Workflows.ps1 | 16 + .../Properties/AssemblyInfo.cs | 2 +- Granfeldt.FIM.ActivityLibrary/Tracer.cs | 75 +++++ 40 files changed, 4428 insertions(+), 231 deletions(-) create mode 100644 ..svnbridge/Granfeldt.FIM.ActivityLibrary.v11.suo create mode 100644 ..svnbridge/Granfeldt.FIM.ActivityLibrary.v12.suo create mode 100644 .vs/Granfeldt.FIM.ActivityLibrary/v14/..svnbridge/.suo create mode 100644 .vs/Granfeldt.FIM.ActivityLibrary/v14/.suo create mode 100644 Granfeldt.FIM.ActivityLibrary.v11.suo create mode 100644 Granfeldt.FIM.ActivityLibrary.v12.suo create mode 100644 Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/BackReferenceUpdateMemberActivity.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/BackReferenceUpdateMemberActivity.designer.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/BackReferenceUpdateMemberActivity.rules create mode 100644 Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/BackReferenceUpdateMemberSettingsPart.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/GetReferenceValuesFromObjectActivity.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/GetReferenceValuesFromObjectActivity.designer.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/GetUpdatesToReferenceAttributeActivity.Designer.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/GetUpdatesToReferenceAttributeActivity.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/UpdateReferenceAttributeActivity.Designer.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/UpdateReferenceAttributeActivity.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/UpdateReferenceAttributesAsNeededActivity.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/UpdateReferenceAttributesAsNeededActivity.designer.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Activity.AddRemoveFromMultivalue/Activity.AddRemoveFromMultiValue.Designer.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Activity.AddRemoveFromMultivalue/Activity.AddRemoveFromMultiValue.SettingsPart.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Activity.AddRemoveFromMultivalue/Activity.AddRemoveFromMultiValue.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Activity.ClearSingleValueAttribute/Activity.ClearSingleValuedAttribute.Designer.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Activity.ClearSingleValueAttribute/Activity.ClearSingleValuedAttribute.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Activity.ClearSingleValueAttribute/ClearSingleValuedAttributeActivitySettingsPart.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Base/Helper.AddRemoveMultiValueAsNeededActivity.Designer.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Base/Helper.AddRemoveMultiValueAsNeededActivity.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Customer.ReconcileSoftwareGroupMembers/Customer.ReconcileSoftwareGroupMembers.Designer.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Customer.ReconcileSoftwareGroupMembers/Customer.ReconcileSoftwareGroupMembers.SettingsPart.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Customer.ReconcileSoftwareGroupMembers/Customer.ReconcileSoftwareGroupMembers.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Customer.UpdateReferenceOnRegExMatch/UpdateReferenceOnRegExMatchActivity.Designer.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Customer.UpdateReferenceOnRegExMatch/UpdateReferenceOnRegExMatchActivity.SettingsPart.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Customer.UpdateReferenceOnRegExMatch/UpdateReferenceOnRegExMatchActivity.cs create mode 100644 Granfeldt.FIM.ActivityLibrary/Tracer.cs diff --git a/..svnbridge/Granfeldt.FIM.ActivityLibrary.v11.suo b/..svnbridge/Granfeldt.FIM.ActivityLibrary.v11.suo new file mode 100644 index 0000000..81efb3c --- /dev/null +++ b/..svnbridge/Granfeldt.FIM.ActivityLibrary.v11.suo @@ -0,0 +1 @@ +svn:mime-typeapplication/octet-stream \ No newline at end of file diff --git a/..svnbridge/Granfeldt.FIM.ActivityLibrary.v12.suo b/..svnbridge/Granfeldt.FIM.ActivityLibrary.v12.suo new file mode 100644 index 0000000..81efb3c --- /dev/null +++ b/..svnbridge/Granfeldt.FIM.ActivityLibrary.v12.suo @@ -0,0 +1 @@ +svn:mime-typeapplication/octet-stream \ No newline at end of file diff --git a/.vs/Granfeldt.FIM.ActivityLibrary/v14/..svnbridge/.suo b/.vs/Granfeldt.FIM.ActivityLibrary/v14/..svnbridge/.suo new file mode 100644 index 0000000..81efb3c --- /dev/null +++ b/.vs/Granfeldt.FIM.ActivityLibrary/v14/..svnbridge/.suo @@ -0,0 +1 @@ +svn:mime-typeapplication/octet-stream \ No newline at end of file diff --git a/.vs/Granfeldt.FIM.ActivityLibrary/v14/.suo b/.vs/Granfeldt.FIM.ActivityLibrary/v14/.suo new file mode 100644 index 0000000000000000000000000000000000000000..53b64d88ef6c9cb77288eff0dd10c61b55e50a88 GIT binary patch literal 205312 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 E|L12xy#N3J literal 0 HcmV?d00001 diff --git a/Granfeldt.FIM.ActivityLibrary.v11.suo b/Granfeldt.FIM.ActivityLibrary.v11.suo new file mode 100644 index 0000000000000000000000000000000000000000..d7a02e3b58ef6e090ced5310eb23e562e9ee597c GIT binary patch literal 191488 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

8yKK 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 Tx}M)}f2P-Q3SaYbftmXskenHv literal 0 HcmV?d00001 diff --git a/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/BackReferenceUpdateMemberActivity.cs b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/BackReferenceUpdateMemberActivity.cs new file mode 100644 index 0000000..ee814dc --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/BackReferenceUpdateMemberActivity.cs @@ -0,0 +1,197 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Linq; +using System.Workflow.Activities; +using System.Workflow.Activities.Rules; +using System.Workflow.ComponentModel; +using System.Workflow.ComponentModel.Compiler; +using System.Workflow.ComponentModel.Design; +using System.Workflow.ComponentModel.Serialization; +using System.Workflow.Runtime; +using Microsoft.ResourceManagement.WebServices.WSResourceManagement; +using Microsoft.ResourceManagement.Workflow.Activities; + +namespace Granfeldt.FIM.ActivityLibrary +{ + public partial class BackReferenceUpdateMemberActivity : SequenceActivity + { + public BackReferenceUpdateMemberActivity() + { + InitializeComponent(); + } + + public static DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(BackReferenceUpdateMemberActivity)); + + [Description("Title")] + [Category("Title Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public string Title + { + get + { + return ((string)(base.GetValue(BackReferenceUpdateMemberActivity.TitleProperty))); + } + set + { + base.SetValue(BackReferenceUpdateMemberActivity.TitleProperty, value); + } + } + + public static DependencyProperty ActionProperty = DependencyProperty.Register("Action", typeof(string), typeof(BackReferenceUpdateMemberActivity)); + [Description("Action")] + [Category("Action Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public string Action + { + get + { + return ((string)(base.GetValue(BackReferenceUpdateMemberActivity.ActionProperty))); + } + set + { + base.SetValue(BackReferenceUpdateMemberActivity.ActionProperty, value); + } + } + + public static DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(string), typeof(BackReferenceUpdateMemberActivity)); + [Description("Source")] + [Category("Source Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public string Source + { + get + { + return ((string)(base.GetValue(BackReferenceUpdateMemberActivity.SourceProperty))); + } + set + { + base.SetValue(BackReferenceUpdateMemberActivity.SourceProperty, value); + } + } + + public static DependencyProperty DestinationProperty = DependencyProperty.Register("Destination", typeof(string), typeof(BackReferenceUpdateMemberActivity)); + [Description("Destination")] + [Category("Destination Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public string Destination + { + get + { + return ((string)(base.GetValue(BackReferenceUpdateMemberActivity.DestinationProperty))); + } + set + { + base.SetValue(BackReferenceUpdateMemberActivity.DestinationProperty, value); + } + } + + public List GroupToUpdate = null; + public Guid CurrentGroupToUpdate; + + private void ForEveryAdd_Condition(object sender, ConditionalEventArgs e) + { + Debugging.Log("Enter::ForEveryAdd_Condition"); + // if not initialized, then initialize and load value into List + if (GroupToUpdate == null) + { + GroupToUpdate = new List(this.GetReferenceUpdates.AddedReferences); + } + + Debugging.Log(string.Format("Count: {0}", GroupToUpdate.Count)); + if (GroupToUpdate.Count > 0) + { + // removed processed item + CurrentGroupToUpdate = GroupToUpdate[0]; + GroupToUpdate.RemoveAt(0); + e.Result = true; + } + else + { + // no more items to process + e.Result = false; + } + Debugging.Log("Exit::ForEveryAdd_Condition"); + } + + private void PrepareGroupOperation_ExecuteCode(object sender, EventArgs e) + { + Debugging.Log("Enter::PrepareGroupOperation_ExecuteCode"); + try + { + // since we're in a while loop, we have to grab the instantiated workflow activity UpdateResourceActivity + SequenceActivity currentParentSequenceActivity = (SequenceActivity)((CodeActivity)sender).Parent; + + UpdateReferenceAttributesAsNeededActivity currentUpdateResourceActivity = currentParentSequenceActivity.Activities.OfType().First(); + + SequentialWorkflow containingWorkflow = null; + if (!SequentialWorkflow.TryGetContainingWorkflow(this, out containingWorkflow)) + { + throw new InvalidOperationException("Could not get parent workflow!"); + } + + Debugging.Log(string.Format("Resource Id: {0}", CurrentGroupToUpdate)); + currentUpdateResourceActivity.ActorId = WellKnownGuids.BuiltInSynchronizationAccount; + currentUpdateResourceActivity.ResourceId = CurrentGroupToUpdate; + currentUpdateResourceActivity.AttributeName = this.Destination; + if (this.Action.ToLower() == "add") + { + Debugging.Log(string.Format("Add member: {0}", this.GetReferenceUpdates.ResourceId.ToString())); + currentUpdateResourceActivity.UpdateMode = UpdateMode.Insert; + } + else + { + Debugging.Log(string.Format("Remove member: {0}", this.GetReferenceUpdates.ResourceId.ToString())); + currentUpdateResourceActivity.UpdateMode = UpdateMode.Remove; + } + currentUpdateResourceActivity.Values = new Guid[] { this.GetReferenceUpdates.ResourceId }; + } + catch (Exception ex) + { + Debugging.Log(string.Format("Error: {0}", ex.Message)); + } + Debugging.Log("Exit::PrepareGroupOperation_ExecuteCode"); + } + + private void SetupClearMV_ExecuteCode(object sender, EventArgs e) + { + Debugging.Log("Enter::SetupClearMV_ExecuteCode"); + try + { + SequentialWorkflow containingWorkflow = null; + if (!SequentialWorkflow.TryGetContainingWorkflow(this, out containingWorkflow)) + { + throw new InvalidOperationException("Could not get parent workflow!"); + } + ClearMVOnResource.ActorId = WellKnownGuids.BuiltInSynchronizationAccount; + ClearMVOnResource.ResourceId = containingWorkflow.TargetId; + int numOfElements = this.GetReferenceUpdates.AddedReferences.ToList().Count; + Debugging.Log(string.Format("List count: {0}", this.GetReferenceUpdates.AddedReferences.ToList().Count)); + Debugging.Log(string.Format("Remove elements: {0}", numOfElements)); + + List ps = new List(); + foreach (Guid value in this.GetReferenceUpdates.AddedReferences.ToList()) + { + Debugging.Log(string.Format("Removing: {0}", value)); + UpdateRequestParameter p = new UpdateRequestParameter(); + p.PropertyName = this.Source; + p.Mode = UpdateMode.Remove; + p.Value = value; + ps.Add(p); + } + ClearMVOnResource.UpdateParameters = ps.ToArray(); + } + catch (Exception ex) + { + Debugging.Log(string.Format("Error: {0}", ex.Message)); + } + Debugging.Log("Exit::SetupClearMV_ExecuteCode"); + } + } +} diff --git a/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/BackReferenceUpdateMemberActivity.designer.cs b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/BackReferenceUpdateMemberActivity.designer.cs new file mode 100644 index 0000000..a560017 --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/BackReferenceUpdateMemberActivity.designer.cs @@ -0,0 +1,206 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Collections; +using System.Reflection; +using System.Workflow.ComponentModel; +using System.Workflow.ComponentModel.Design; +using System.Workflow.ComponentModel.Compiler; +using System.Workflow.ComponentModel.Serialization; +using System.Workflow.Runtime; +using System.Workflow.Activities; +using System.Workflow.Activities.Rules; + +namespace Granfeldt.FIM.ActivityLibrary +{ + public partial class BackReferenceUpdateMemberActivity + { + #region Designer generated code + + ///

+ /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + [System.Diagnostics.DebuggerNonUserCode] + [System.CodeDom.Compiler.GeneratedCode("", "")] + private void InitializeComponent() + { + this.CanModifyActivities = true; + System.Workflow.Activities.CodeCondition codecondition1 = new System.Workflow.Activities.CodeCondition(); + System.Workflow.Activities.CodeCondition codecondition2 = new System.Workflow.Activities.CodeCondition(); + System.Workflow.Activities.Rules.RuleConditionReference ruleconditionreference1 = new System.Workflow.Activities.Rules.RuleConditionReference(); + System.Workflow.ComponentModel.ActivityBind activitybind1 = new System.Workflow.ComponentModel.ActivityBind(); + this.RemoveFromTarget = new Granfeldt.FIM.ActivityLibrary.UpdateReferenceAttributesAsNeededActivity(); + this.PrepareGroupRemoveOperation = new System.Workflow.Activities.CodeActivity(); + this.AddToTarget = new Granfeldt.FIM.ActivityLibrary.UpdateReferenceAttributesAsNeededActivity(); + this.PrepareGroupAddOperation = new System.Workflow.Activities.CodeActivity(); + this.RemoveActivity = new System.Workflow.Activities.SequenceActivity(); + this.AddingActivity = new System.Workflow.Activities.SequenceActivity(); + this.ForEachMemberToRemove = new System.Workflow.Activities.WhileActivity(); + this.ForEachMemberToAdd = new System.Workflow.Activities.WhileActivity(); + this.ClearMVOnResource = new Microsoft.ResourceManagement.Workflow.Activities.UpdateResourceActivity(); + this.SetupClearMV = new System.Workflow.Activities.CodeActivity(); + this.Remove = new System.Workflow.Activities.IfElseBranchActivity(); + this.Add = new System.Workflow.Activities.IfElseBranchActivity(); + this.ClearMultivalueAttribute = new System.Workflow.Activities.SequenceActivity(); + this.ifElseActivity1 = new System.Workflow.Activities.IfElseActivity(); + this.GetReferenceUpdates = new Granfeldt.FIM.ActivityLibrary.GetUpdatesToReferenceAttributeActivity(); + // + // RemoveFromTarget + // + this.RemoveFromTarget.ActorId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.RemoveFromTarget.AttributeName = null; + this.RemoveFromTarget.Name = "RemoveFromTarget"; + this.RemoveFromTarget.ResourceId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.RemoveFromTarget.UpdateMode = Microsoft.ResourceManagement.WebServices.WSResourceManagement.UpdateMode.Modify; + this.RemoveFromTarget.Values = null; + // + // PrepareGroupRemoveOperation + // + this.PrepareGroupRemoveOperation.Name = "PrepareGroupRemoveOperation"; + this.PrepareGroupRemoveOperation.ExecuteCode += new System.EventHandler(this.PrepareGroupOperation_ExecuteCode); + // + // AddToTarget + // + this.AddToTarget.ActorId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.AddToTarget.AttributeName = null; + this.AddToTarget.Name = "AddToTarget"; + this.AddToTarget.ResourceId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.AddToTarget.UpdateMode = Microsoft.ResourceManagement.WebServices.WSResourceManagement.UpdateMode.Modify; + this.AddToTarget.Values = null; + // + // PrepareGroupAddOperation + // + this.PrepareGroupAddOperation.Name = "PrepareGroupAddOperation"; + this.PrepareGroupAddOperation.ExecuteCode += new System.EventHandler(this.PrepareGroupOperation_ExecuteCode); + // + // RemoveActivity + // + this.RemoveActivity.Activities.Add(this.PrepareGroupRemoveOperation); + this.RemoveActivity.Activities.Add(this.RemoveFromTarget); + this.RemoveActivity.Name = "RemoveActivity"; + // + // AddingActivity + // + this.AddingActivity.Activities.Add(this.PrepareGroupAddOperation); + this.AddingActivity.Activities.Add(this.AddToTarget); + this.AddingActivity.Name = "AddingActivity"; + // + // ForEachMemberToRemove + // + this.ForEachMemberToRemove.Activities.Add(this.RemoveActivity); + codecondition1.Condition += new System.EventHandler(this.ForEveryAdd_Condition); + this.ForEachMemberToRemove.Condition = codecondition1; + this.ForEachMemberToRemove.Name = "ForEachMemberToRemove"; + // + // ForEachMemberToAdd + // + this.ForEachMemberToAdd.Activities.Add(this.AddingActivity); + codecondition2.Condition += new System.EventHandler(this.ForEveryAdd_Condition); + this.ForEachMemberToAdd.Condition = codecondition2; + this.ForEachMemberToAdd.Name = "ForEachMemberToAdd"; + // + // ClearMVOnResource + // + this.ClearMVOnResource.ActorId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.ClearMVOnResource.Name = "ClearMVOnResource"; + this.ClearMVOnResource.ResourceId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.ClearMVOnResource.UpdateParameters = null; + // + // SetupClearMV + // + this.SetupClearMV.Name = "SetupClearMV"; + this.SetupClearMV.ExecuteCode += new System.EventHandler(this.SetupClearMV_ExecuteCode); + // + // Remove + // + this.Remove.Activities.Add(this.ForEachMemberToRemove); + this.Remove.Name = "Remove"; + // + // Add + // + this.Add.Activities.Add(this.ForEachMemberToAdd); + ruleconditionreference1.ConditionName = "Condition1"; + this.Add.Condition = ruleconditionreference1; + this.Add.Name = "Add"; + // + // ClearMultivalueAttribute + // + this.ClearMultivalueAttribute.Activities.Add(this.SetupClearMV); + this.ClearMultivalueAttribute.Activities.Add(this.ClearMVOnResource); + this.ClearMultivalueAttribute.Name = "ClearMultivalueAttribute"; + // + // ifElseActivity1 + // + this.ifElseActivity1.Activities.Add(this.Add); + this.ifElseActivity1.Activities.Add(this.Remove); + this.ifElseActivity1.Name = "ifElseActivity1"; + // + // GetReferenceUpdates + // + this.GetReferenceUpdates.AddedReferences = null; + activitybind1.Name = "BackReferenceUpdateMemberActivity"; + activitybind1.Path = "Source"; + this.GetReferenceUpdates.ModifiedReferences = null; + this.GetReferenceUpdates.Name = "GetReferenceUpdates"; + this.GetReferenceUpdates.OperationType = Microsoft.ResourceManagement.WebServices.WSResourceManagement.OperationType.Create; + this.GetReferenceUpdates.RemovedReferences = null; + this.GetReferenceUpdates.ResourceId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.GetReferenceUpdates.SetBinding(Granfeldt.FIM.ActivityLibrary.GetUpdatesToReferenceAttributeActivity.AttributeNameProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind1))); + // + // BackReferenceUpdateMemberActivity + // + this.Activities.Add(this.GetReferenceUpdates); + this.Activities.Add(this.ifElseActivity1); + this.Activities.Add(this.ClearMultivalueAttribute); + this.Name = "BackReferenceUpdateMemberActivity"; + this.CanModifyActivities = false; + + } + + #endregion + + private CodeActivity SetupClearMV; + + private SequenceActivity ClearMultivalueAttribute; + + private Microsoft.ResourceManagement.Workflow.Activities.UpdateResourceActivity ClearMVOnResource; + + private IfElseBranchActivity Remove; + + private IfElseBranchActivity Add; + + private IfElseActivity ifElseActivity1; + + private UpdateReferenceAttributesAsNeededActivity RemoveFromTarget; + + private CodeActivity PrepareGroupRemoveOperation; + + private SequenceActivity RemoveActivity; + + private WhileActivity ForEachMemberToRemove; + + private UpdateReferenceAttributesAsNeededActivity AddToTarget; + + private CodeActivity PrepareGroupAddOperation; + + private SequenceActivity AddingActivity; + + private WhileActivity ForEachMemberToAdd; + + private GetUpdatesToReferenceAttributeActivity GetReferenceUpdates; + + + + + + + + + + + + + + } +} diff --git a/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/BackReferenceUpdateMemberActivity.rules b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/BackReferenceUpdateMemberActivity.rules new file mode 100644 index 0000000..9b9296b --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/BackReferenceUpdateMemberActivity.rules @@ -0,0 +1,32 @@ + + + + + + + + + add + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/BackReferenceUpdateMemberSettingsPart.cs b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/BackReferenceUpdateMemberSettingsPart.cs new file mode 100644 index 0000000..300b2f0 --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/BackReferenceUpdateMemberSettingsPart.cs @@ -0,0 +1,197 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web.UI; +using System.Web.UI.WebControls; +using System.Workflow.ComponentModel; +using Microsoft.IdentityManagement.WebUI.Controls; +using Microsoft.ResourceManagement.Workflow.Activities; + +namespace Granfeldt.FIM.ActivityLibrary.WebUIs +{ + class BackReferenceUpdateMemberActivitySettingsPart : ActivitySettingsPart + { + + /// + /// Creates a Table that contains the controls used by the activity UI + /// in the Workflow Designer of the FIM portal. Adds that Table to the + /// collection of Controls that defines each activity that can be selected + /// in the Workflow Designer of the FIM Portal. Calls the base class of + /// ActivitySettingsPart to render the controls in the UI. + /// + protected override void CreateChildControls() + { + Table controlLayoutTable; + controlLayoutTable = new Table(); + + //Width is set to 100% of the control size + controlLayoutTable.Width = Unit.Percentage(100.0); + controlLayoutTable.BorderWidth = 0; + controlLayoutTable.CellPadding = 2; + //Add a TableRow for each textbox in the UI + controlLayoutTable.Rows.Add(this.AddTableRowTextBox("Title:", "txtTitle", 400, 100, false, "")); + controlLayoutTable.Rows.Add(this.AddTableRowTextBox("Source reference attribute:", "txtSource", 400, 100, false, "")); + controlLayoutTable.Rows.Add(this.AddTableRowTextBox("Destination attribute:", "txtDestination", 400, 100, false, "")); + controlLayoutTable.Rows.Add(this.AddTableRowTextBox("Action (type 'add' or 'remove'):", "txtAction", 400, 100, false, "")); + this.Controls.Add(controlLayoutTable); + + base.CreateChildControls(); + } + + #region Utility Functions + + //Create a TableRow that contains a label and a textbox. + private TableRow AddTableRowTextBox(String labelText, String controlID, int width, int maxLength, Boolean multiLine, String defaultValue) + { + TableRow row = new TableRow(); + TableCell labelCell = new TableCell(); + TableCell controlCell = new TableCell(); + Label oLabel = new Label(); + TextBox oText = new TextBox(); + + oLabel.Text = labelText; + oLabel.CssClass = base.LabelCssClass; + labelCell.Controls.Add(oLabel); + oText.ID = controlID; + oText.CssClass = base.TextBoxCssClass; + oText.Text = defaultValue; + oText.MaxLength = maxLength; + oText.Width = width; + if (multiLine) + { + oText.TextMode = TextBoxMode.MultiLine; + oText.Rows = System.Math.Min(6, (maxLength + 60) / 60); + oText.Wrap = true; + } + controlCell.Controls.Add(oText); + row.Cells.Add(labelCell); + row.Cells.Add(controlCell); + return row; + } + + string GetText(string textBoxID) + { + TextBox textBox = (TextBox)this.FindControl(textBoxID); + return textBox.Text ?? String.Empty; + } + void SetText(string textBoxID, string text) + { + TextBox textBox = (TextBox)this.FindControl(textBoxID); + if (textBox != null) + textBox.Text = text; + else + textBox.Text = ""; + } + + //Set the text box to read mode or read/write mode + void SetTextBoxReadOnlyOption(string textBoxID, bool readOnly) + { + TextBox textBox = (TextBox)this.FindControl(textBoxID); + textBox.ReadOnly = readOnly; + } + #endregion + + /// + /// Called when a user clicks the Save button in the Workflow Designer. + /// Returns an instance of the RequestLoggingActivity class that + /// has its properties set to the values entered into the text box controls + /// used in the UI of the activity. + /// + public override Activity GenerateActivityOnWorkflow(SequentialWorkflow workflow) + { + if (!this.ValidateInputs()) + { + return null; + } + BackReferenceUpdateMemberActivity ThisActivity = new BackReferenceUpdateMemberActivity(); + ThisActivity.Title = this.GetText("txtTitle"); + ThisActivity.Source = this.GetText("txtSource"); + ThisActivity.Destination = this.GetText("txtDestination"); + ThisActivity.Action = this.GetText("txtAction"); + return ThisActivity; + } + + public override void LoadActivitySettings(Activity activity) + { + BackReferenceUpdateMemberActivity ThisActivity = activity as BackReferenceUpdateMemberActivity; + if (ThisActivity != null) + { + this.SetText("txtTitle", ThisActivity.Title); + this.SetText("txtSource", ThisActivity.Source); + this.SetText("txtDestination", ThisActivity.Destination); + this.SetText("txtAction", ThisActivity.Action); + } + } + + /// + /// Saves the activity settings. + /// + public override ActivitySettingsPartData PersistSettings() + { + ActivitySettingsPartData data = new ActivitySettingsPartData(); + data["Title"] = this.GetText("txtTitle"); + data["Source"] = this.GetText("txtSource"); + data["Attribute"] = this.GetText("txtDestination"); + data["Action"] = this.GetText("txtAction"); + return data; + } + + /// + /// Restores the activity settings in the UI + /// + public override void RestoreSettings(ActivitySettingsPartData data) + { + if (null != data) + { + this.SetText("txtTitle", (string)data["Title"]); + this.SetText("txtSource", (string)data["Source"]); + this.SetText("txtDestination", (string)data["Attribute"]); + this.SetText("txtAction", (string)data["Action"]); + } + } + + /// + /// Switches the activity between read only and read/write mode + /// + public override void SwitchMode(ActivitySettingsPartMode mode) + { + bool readOnly = (mode == ActivitySettingsPartMode.View); + this.SetTextBoxReadOnlyOption("txtTitle", readOnly); + this.SetTextBoxReadOnlyOption("txtDestination", readOnly); + this.SetTextBoxReadOnlyOption("txtSource", readOnly); + this.SetTextBoxReadOnlyOption("txtAction", readOnly); + } + + /// + /// Returns the activity name. + /// + public override string Title + { + get + { + return string.Format("Add Remove Value: {0}", this.GetText("txtTitle")); + } + } + + /// + /// In general, this method should be used to validate information entered + /// by the user when the activity is added to a workflow in the Workflow + /// Designer. + /// We could add code to verify that the log file path already exists on + /// the server that is hosting the FIM Portal and check that the activity + /// has permission to write to that location. However, the code + /// would only check if the log file path exists when the + /// activity is added to a workflow in the workflow designer. This class + /// will not be used when the activity is actually run. + /// For this activity we will just return true. + /// + public override bool ValidateInputs() + { + return true; + } + + } + + +} diff --git a/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/GetReferenceValuesFromObjectActivity.cs b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/GetReferenceValuesFromObjectActivity.cs new file mode 100644 index 0000000..eb84ca1 --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/GetReferenceValuesFromObjectActivity.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Linq; +using System.Workflow.Activities; +using System.Workflow.ComponentModel; +using System.Workflow.ComponentModel.Design; + +namespace Granfeldt.FIM.ActivityLibrary +{ + [Designer(typeof(ActivityDesigner), typeof(IDesigner))] + public partial class GetReferenceValuesFromObjectActivity: SequenceActivity + { + #region Properties + + + public static DependencyProperty ObjectIDProperty = DependencyProperty.Register("ObjectID", typeof(Guid), typeof(GetReferenceValuesFromObjectActivity)); + + [Description("ObjectID")] + [Category("Input")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Guid ObjectID + { + get + { + return ((Guid)(base.GetValue(GetReferenceValuesFromObjectActivity.ObjectIDProperty))); + } + set + { + base.SetValue(GetReferenceValuesFromObjectActivity.ObjectIDProperty, value); + } + } + + public static DependencyProperty AttributeNameProperty = DependencyProperty.Register("AttributeName", typeof(String), typeof(GetReferenceValuesFromObjectActivity)); + + [Description("AttributeName")] + [Category("Input")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public String AttributeName + { + get + { + return ((String)(base.GetValue(GetReferenceValuesFromObjectActivity.AttributeNameProperty))); + } + set + { + base.SetValue(GetReferenceValuesFromObjectActivity.AttributeNameProperty, value); + } + } + + public static DependencyProperty ActorIdProperty = DependencyProperty.Register("ActorId", typeof(Guid), typeof(GetReferenceValuesFromObjectActivity)); + + [Description("ActorId")] + [Category("Input")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Guid ActorId + { + get + { + return ((Guid)(base.GetValue(GetReferenceValuesFromObjectActivity.ActorIdProperty))); + } + set + { + base.SetValue(GetReferenceValuesFromObjectActivity.ActorIdProperty, value); + } + } + + public static DependencyProperty CurrentValuesProperty = DependencyProperty.Register("CurrentValues", typeof(Guid[]), typeof(GetReferenceValuesFromObjectActivity)); + + [Description("CurrentValues")] + [Category("Output")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Guid[] CurrentValues + { + get + { + return ((Guid[])(base.GetValue(GetReferenceValuesFromObjectActivity.CurrentValuesProperty))); + } + set + { + base.SetValue(GetReferenceValuesFromObjectActivity.CurrentValuesProperty, value); + } + } + + #endregion + + public GetReferenceValuesFromObjectActivity() + { + InitializeComponent(); + } + + public String[] SelectionAttributes = default(System.String[]); + public Microsoft.ResourceManagement.WebServices.WSResourceManagement.ResourceType CurrentResource = new Microsoft.ResourceManagement.WebServices.WSResourceManagement.ResourceType(); + + private void PrepareReading_ExecuteCode(object sender, EventArgs e) + { + this.SelectionAttributes = new string[] {this.AttributeName}; + } + + private void ProcessResults_ExecuteCode(object sender, EventArgs e) + { + object PropertyValue = this.CurrentResource[this.AttributeName]; + List currentValues = new List(); + + if (null != PropertyValue) + { + if (PropertyValue.GetType().FullName.StartsWith("System.Collections.Generic.List") || + PropertyValue.GetType().FullName.EndsWith("[]")) + { + foreach (object myObject in (IEnumerable) PropertyValue) + { + if (myObject is Microsoft.ResourceManagement.WebServices.UniqueIdentifier) + { + currentValues.Add( + ((Microsoft.ResourceManagement.WebServices.UniqueIdentifier) myObject).GetGuid()); + } + if (myObject is System.Guid) + { + currentValues.Add((System.Guid) myObject); + } + + } + } + else + { + if (PropertyValue is Microsoft.ResourceManagement.WebServices.UniqueIdentifier) + { + currentValues.Add( + ((Microsoft.ResourceManagement.WebServices.UniqueIdentifier) PropertyValue).GetGuid()); + } + if (PropertyValue is System.Guid) + { + currentValues.Add((System.Guid) PropertyValue); + } + } + } + + this.CurrentValues = currentValues.Distinct().ToArray(); + } + } +} \ No newline at end of file diff --git a/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/GetReferenceValuesFromObjectActivity.designer.cs b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/GetReferenceValuesFromObjectActivity.designer.cs new file mode 100644 index 0000000..4a043b7 --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/GetReferenceValuesFromObjectActivity.designer.cs @@ -0,0 +1,75 @@ +using System.Workflow.Activities; + +namespace Granfeldt.FIM.ActivityLibrary +{ + public partial class GetReferenceValuesFromObjectActivity + { + #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; + System.Workflow.ComponentModel.ActivityBind activitybind1 = new System.Workflow.ComponentModel.ActivityBind(); + System.Workflow.ComponentModel.ActivityBind activitybind2 = new System.Workflow.ComponentModel.ActivityBind(); + System.Workflow.ComponentModel.ActivityBind activitybind3 = new System.Workflow.ComponentModel.ActivityBind(); + System.Workflow.ComponentModel.ActivityBind activitybind4 = new System.Workflow.ComponentModel.ActivityBind(); + this.ProcessResults = new System.Workflow.Activities.CodeActivity(); + this.ReadResource = new Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity(); + this.PrepareReading = new System.Workflow.Activities.CodeActivity(); + // + // ProcessResults + // + this.ProcessResults.Name = "ProcessResults"; + this.ProcessResults.ExecuteCode += new System.EventHandler(this.ProcessResults_ExecuteCode); + // + // ReadResource + // + activitybind1.Name = "GetReferenceValuesFromObjectActivity"; + activitybind1.Path = "ActorId"; + this.ReadResource.Name = "ReadResource"; + activitybind2.Name = "GetReferenceValuesFromObjectActivity"; + activitybind2.Path = "CurrentResource"; + activitybind3.Name = "GetReferenceValuesFromObjectActivity"; + activitybind3.Path = "ObjectID"; + activitybind4.Name = "GetReferenceValuesFromObjectActivity"; + activitybind4.Path = "SelectionAttributes"; + this.ReadResource.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity.ActorIdProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind1))); + this.ReadResource.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity.ResourceIdProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind3))); + //this.ReadResource.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity.SelectionAttributesProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind4))); + this.ReadResource.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity.ResourceProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind2))); + // + // PrepareReading + // + this.PrepareReading.Name = "PrepareReading"; + this.PrepareReading.ExecuteCode += new System.EventHandler(this.PrepareReading_ExecuteCode); + // + // GetReferenceValuesFromObjectActivity + // + this.Activities.Add(this.PrepareReading); + this.Activities.Add(this.ReadResource); + this.Activities.Add(this.ProcessResults); + this.Name = "GetReferenceValuesFromObjectActivity"; + this.CanModifyActivities = false; + + } + + #endregion + + private CodeActivity PrepareReading; + private CodeActivity ProcessResults; + private Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity ReadResource; + + + + + + + + + } +} \ No newline at end of file diff --git a/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/GetUpdatesToReferenceAttributeActivity.Designer.cs b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/GetUpdatesToReferenceAttributeActivity.Designer.cs new file mode 100644 index 0000000..83a9cc1 --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/GetUpdatesToReferenceAttributeActivity.Designer.cs @@ -0,0 +1,48 @@ +using System.Workflow.Activities; + +namespace Granfeldt.FIM.ActivityLibrary +{ + public partial class GetUpdatesToReferenceAttributeActivity + { + #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; + System.Workflow.ComponentModel.ActivityBind activitybind1 = new System.Workflow.ComponentModel.ActivityBind(); + this.ExtractDataFromRequest = new System.Workflow.Activities.CodeActivity(); + this.GetCurrentRequest = new Microsoft.ResourceManagement.Workflow.Activities.CurrentRequestActivity(); + // + // ExtractDataFromRequest + // + this.ExtractDataFromRequest.Name = "ExtractDataFromRequest"; + this.ExtractDataFromRequest.ExecuteCode += new System.EventHandler(this.ExtractDataFromRequest_ExecuteCode); + // + // GetCurrentRequest + // + activitybind1.Name = "GetUpdatesToReferenceAttributeActivity"; + activitybind1.Path = "CurrentRequest"; + this.GetCurrentRequest.Name = "GetCurrentRequest"; + this.GetCurrentRequest.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.CurrentRequestActivity.CurrentRequestProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind1))); + // + // GetUpdatesToReferenceAttributeActivity + // + this.Activities.Add(this.GetCurrentRequest); + this.Activities.Add(this.ExtractDataFromRequest); + this.Name = "GetUpdatesToReferenceAttributeActivity"; + this.CanModifyActivities = false; + + } + + #endregion + + private CodeActivity ExtractDataFromRequest; + private Microsoft.ResourceManagement.Workflow.Activities.CurrentRequestActivity GetCurrentRequest; + + } +} \ No newline at end of file diff --git a/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/GetUpdatesToReferenceAttributeActivity.cs b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/GetUpdatesToReferenceAttributeActivity.cs new file mode 100644 index 0000000..ffd6c5d --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/GetUpdatesToReferenceAttributeActivity.cs @@ -0,0 +1,289 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Linq; +using System.Workflow.Activities; +using System.Workflow.ComponentModel; +using System.Workflow.ComponentModel.Design; +using Microsoft.ResourceManagement.WebServices.WSResourceManagement; + +namespace Granfeldt.FIM.ActivityLibrary +{ + [Designer(typeof(ActivityDesigner), typeof(IDesigner))] + public partial class GetUpdatesToReferenceAttributeActivity : SequenceActivity + { + + #region Properties + public static DependencyProperty AddedReferencesProperty = DependencyProperty.Register("AddedReferences", typeof(Guid[]), typeof(GetUpdatesToReferenceAttributeActivity)); + + [Description("AddedReferences")] + [Category("Output")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Guid[] AddedReferences + { + get + { + return ((Guid[])(base.GetValue(GetUpdatesToReferenceAttributeActivity.AddedReferencesProperty))); + } + set + { + base.SetValue(GetUpdatesToReferenceAttributeActivity.AddedReferencesProperty, value); + } + } + + public static DependencyProperty ModifiedReferencesProperty = DependencyProperty.Register("ModifiedReferences", typeof(Guid[]), typeof(GetUpdatesToReferenceAttributeActivity)); + + [DescriptionAttribute("ModifiedReferences")] + [CategoryAttribute("Output")] + [BrowsableAttribute(true)] + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] + public Guid[] ModifiedReferences + { + get + { + return ((Guid[])(base.GetValue(GetUpdatesToReferenceAttributeActivity.ModifiedReferencesProperty))); + } + set + { + base.SetValue(GetUpdatesToReferenceAttributeActivity.ModifiedReferencesProperty, value); + } + } + + public static DependencyProperty RemovedReferencesProperty = DependencyProperty.Register("RemovedReferences", typeof(Guid[]), typeof(GetUpdatesToReferenceAttributeActivity)); + + public static DependencyProperty ResourceIdProperty = DependencyProperty.Register("ResourceId", typeof(Guid), typeof(GetUpdatesToReferenceAttributeActivity)); + + [Description("ResourceId")] + [Category("Output")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Guid ResourceId + { + get + { + return ((Guid)(base.GetValue(GetUpdatesToReferenceAttributeActivity.ResourceIdProperty))); + } + set + { + base.SetValue(GetUpdatesToReferenceAttributeActivity.ResourceIdProperty, value); + } + } + + [Description("RemovedReferences")] + [Category("Output")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Guid[] RemovedReferences + { + get + { + return ((Guid[])(base.GetValue(GetUpdatesToReferenceAttributeActivity.RemovedReferencesProperty))); + } + set + { + base.SetValue(GetUpdatesToReferenceAttributeActivity.RemovedReferencesProperty, value); + } + } + + public static DependencyProperty AttributeNameProperty = DependencyProperty.Register("AttributeName", typeof(string), typeof(GetUpdatesToReferenceAttributeActivity)); + + [Description("AttributeName")] + [Category("Input")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public string AttributeName + { + get + { + return ((string)(base.GetValue(GetUpdatesToReferenceAttributeActivity.AttributeNameProperty))); + } + set + { + base.SetValue(GetUpdatesToReferenceAttributeActivity.AttributeNameProperty, value); + } + } + + public static DependencyProperty OperationTypeProperty = DependencyProperty.Register("OperationType", typeof(OperationType), typeof(GetUpdatesToReferenceAttributeActivity)); + + [Description("OperationType")] + [Category("Output")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public OperationType OperationType + { + get + { + return ((OperationType)(base.GetValue(GetUpdatesToReferenceAttributeActivity.OperationTypeProperty))); + } + set + { + base.SetValue(GetUpdatesToReferenceAttributeActivity.OperationTypeProperty, value); + } + } + + #endregion + + public GetUpdatesToReferenceAttributeActivity() + { + InitializeComponent(); + } + + public Microsoft.ResourceManagement.WebServices.WSResourceManagement.RequestType CurrentRequest = null; + + private void ExtractDataFromRequest_ExecuteCode(object sender, EventArgs e) + { + this.ResourceId = this.CurrentRequest.Target.GetGuid(); + this.OperationType = this.CurrentRequest.Operation; + List toAdd = new List(); + List toRemove = new List(); + List toModify = new List(); + + if (this.CurrentRequest.Operation == OperationType.Create) + { + ReadOnlyCollection myParameters = + this.CurrentRequest.ParseParameters(); + + foreach (CreateRequestParameter myParameter in myParameters) + { + if (String.Equals(this.AttributeName, myParameter.PropertyName, + StringComparison.InvariantCultureIgnoreCase)) + { + if (myParameter.Value.GetType().FullName.StartsWith("System.Collections.Generic.List") || + myParameter.Value.GetType().FullName.EndsWith("[]")) + { + foreach (object myObject in (IEnumerable)myParameter.Value) + { + + if (myObject is Microsoft.ResourceManagement.WebServices.UniqueIdentifier) + toAdd.Add( + ((Microsoft.ResourceManagement.WebServices.UniqueIdentifier)myObject).GetGuid()); + if (myObject is System.Guid) + toAdd.Add((System.Guid)myObject); + } + } + else + { + if (myParameter.Value is Microsoft.ResourceManagement.WebServices.UniqueIdentifier) + toAdd.Add( + ((Microsoft.ResourceManagement.WebServices.UniqueIdentifier)myParameter.Value). + GetGuid()); + if (myParameter.Value is System.Guid) + toAdd.Add((System.Guid)myParameter.Value); + } + } + } + } + + if (this.CurrentRequest.Operation == OperationType.Put) + { + ReadOnlyCollection myParameters = + this.CurrentRequest.ParseParameters(); + + foreach (UpdateRequestParameter myParameter in myParameters) + { + if (myParameter.Mode == UpdateMode.Insert) + { + if (String.Equals(this.AttributeName, myParameter.PropertyName, + StringComparison.InvariantCultureIgnoreCase)) + { + if (myParameter.Value.GetType().FullName.StartsWith("System.Collections.Generic.List") || + myParameter.Value.GetType().FullName.EndsWith("[]")) + { + foreach (object myObject in (IEnumerable)myParameter.Value) + { + if (myObject is Microsoft.ResourceManagement.WebServices.UniqueIdentifier) + toAdd.Add( + ((Microsoft.ResourceManagement.WebServices.UniqueIdentifier)myObject). + GetGuid()); + if (myObject is System.Guid) + toAdd.Add((System.Guid)myObject); + } + } + else + { + if (myParameter.Value is Microsoft.ResourceManagement.WebServices.UniqueIdentifier) + toAdd.Add( + ((Microsoft.ResourceManagement.WebServices.UniqueIdentifier)myParameter.Value). + GetGuid()); + if (myParameter.Value is System.Guid) + toAdd.Add((System.Guid)myParameter.Value); + } + } + } + + if (myParameter.Mode == UpdateMode.Modify) + { + if (String.Equals(this.AttributeName, myParameter.PropertyName, + StringComparison.InvariantCultureIgnoreCase)) + { + // Actually never going to happen, but who knows ? + if (myParameter.Value.GetType().FullName.StartsWith("System.Collections.Generic.List") || + myParameter.Value.GetType().FullName.EndsWith("[]")) + { + foreach (object myObject in (IEnumerable)myParameter.Value) + { + + if (myObject is Microsoft.ResourceManagement.WebServices.UniqueIdentifier) + toModify.Add( + ((Microsoft.ResourceManagement.WebServices.UniqueIdentifier)myObject). + GetGuid()); + if (myObject is System.Guid) + toModify.Add((System.Guid)myObject); + } + } + else + { + if (myParameter.Value is Microsoft.ResourceManagement.WebServices.UniqueIdentifier) + toModify.Add( + ((Microsoft.ResourceManagement.WebServices.UniqueIdentifier)myParameter.Value). + GetGuid()); + if (myParameter.Value is System.Guid) + toModify.Add((System.Guid)myParameter.Value); + } + } + } + + + if (myParameter.Mode == UpdateMode.Remove) + { + if (String.Equals(this.AttributeName, myParameter.PropertyName, + StringComparison.InvariantCultureIgnoreCase)) + { + if (myParameter.Value.GetType().FullName.StartsWith("System.Collections.Generic.List") || + myParameter.Value.GetType().FullName.EndsWith("[]")) + { + foreach (object myObject in (IEnumerable)myParameter.Value) + { + + if (myObject is Microsoft.ResourceManagement.WebServices.UniqueIdentifier) + toRemove.Add( + ((Microsoft.ResourceManagement.WebServices.UniqueIdentifier)myObject). + GetGuid()); + if (myObject is System.Guid) + toRemove.Add((System.Guid)myObject); + } + } + else + { + if (myParameter.Value is Microsoft.ResourceManagement.WebServices.UniqueIdentifier) + toRemove.Add( + ((Microsoft.ResourceManagement.WebServices.UniqueIdentifier)myParameter.Value). + GetGuid()); + if (myParameter.Value is System.Guid) + toRemove.Add((System.Guid)myParameter.Value); + } + } + } + + } + } + this.AddedReferences=toAdd.Distinct().ToArray(); + this.RemovedReferences=toRemove.Distinct().ToArray(); + this.ModifiedReferences = toModify.Distinct().ToArray(); + } + } +} \ No newline at end of file diff --git a/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/UpdateReferenceAttributeActivity.Designer.cs b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/UpdateReferenceAttributeActivity.Designer.cs new file mode 100644 index 0000000..9305d43 --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/UpdateReferenceAttributeActivity.Designer.cs @@ -0,0 +1,90 @@ +using System.Workflow.Activities; + +namespace Granfeldt.FIM.ActivityLibrary +{ + public partial class UpdateReferenceAttributeActivity + { + #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; + System.Workflow.ComponentModel.ActivityBind activitybind1 = new System.Workflow.ComponentModel.ActivityBind(); + System.Workflow.ComponentModel.ActivityBind activitybind2 = new System.Workflow.ComponentModel.ActivityBind(); + System.Workflow.ComponentModel.ActivityBind activitybind3 = new System.Workflow.ComponentModel.ActivityBind(); + System.Workflow.Activities.CodeCondition codecondition1 = new System.Workflow.Activities.CodeCondition(); + this.UpdateResource = new Microsoft.ResourceManagement.Workflow.Activities.UpdateResourceActivity(); + this.PrepareUpdate = new System.Workflow.Activities.CodeActivity(); + this.ValuesAreNotPresent = new System.Workflow.Activities.IfElseBranchActivity(); + this.ValuesPresent = new System.Workflow.Activities.IfElseBranchActivity(); + this.CheckIfAnyValuesPresent = new System.Workflow.Activities.IfElseActivity(); + // + // UpdateResource + // + activitybind1.Name = "UpdateReferenceAttributeActivity"; + activitybind1.Path = "ActorId"; + this.UpdateResource.Name = "UpdateResource"; + activitybind2.Name = "UpdateReferenceAttributeActivity"; + activitybind2.Path = "ResourceId"; + activitybind3.Name = "UpdateReferenceAttributeActivity"; + activitybind3.Path = "UpdateParameters"; + this.UpdateResource.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.UpdateResourceActivity.ActorIdProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind1))); + this.UpdateResource.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.UpdateResourceActivity.ResourceIdProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind2))); + this.UpdateResource.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.UpdateResourceActivity.UpdateParametersProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind3))); + // + // PrepareUpdate + // + this.PrepareUpdate.Name = "PrepareUpdate"; + this.PrepareUpdate.ExecuteCode += new System.EventHandler(this.PrepareUpdate_ExecuteCode); + // + // ValuesAreNotPresent + // + this.ValuesAreNotPresent.Name = "ValuesAreNotPresent"; + // + // ValuesPresent + // + this.ValuesPresent.Activities.Add(this.PrepareUpdate); + this.ValuesPresent.Activities.Add(this.UpdateResource); + codecondition1.Condition += new System.EventHandler(this.AreValuesPresent); + this.ValuesPresent.Condition = codecondition1; + this.ValuesPresent.Name = "ValuesPresent"; + // + // CheckIfAnyValuesPresent + // + this.CheckIfAnyValuesPresent.Activities.Add(this.ValuesPresent); + this.CheckIfAnyValuesPresent.Activities.Add(this.ValuesAreNotPresent); + this.CheckIfAnyValuesPresent.Name = "CheckIfAnyValuesPresent"; + // + // UpdateReferenceAttributeActivity + // + this.Activities.Add(this.CheckIfAnyValuesPresent); + this.Name = "UpdateReferenceAttributeActivity"; + this.CanModifyActivities = false; + + } + + #endregion + + private IfElseBranchActivity ValuesAreNotPresent; + private IfElseBranchActivity ValuesPresent; + private IfElseActivity CheckIfAnyValuesPresent; + private CodeActivity PrepareUpdate; + private Microsoft.ResourceManagement.Workflow.Activities.UpdateResourceActivity UpdateResource; + + + + + + + + + + + + } +} \ No newline at end of file diff --git a/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/UpdateReferenceAttributeActivity.cs b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/UpdateReferenceAttributeActivity.cs new file mode 100644 index 0000000..513527d --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/UpdateReferenceAttributeActivity.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Workflow.Activities; +using System.Workflow.ComponentModel; +using System.Workflow.ComponentModel.Design; +using Microsoft.ResourceManagement.WebServices.WSResourceManagement; + +namespace Granfeldt.FIM.ActivityLibrary +{ + [Designer(typeof(ActivityDesigner), typeof(IDesigner))] + public partial class UpdateReferenceAttributeActivity : SequenceActivity + { + #region Properties + public static DependencyProperty ActorIdProperty = DependencyProperty.Register("ActorId", typeof(Guid), typeof(UpdateReferenceAttributeActivity)); + + [Description("ActorId")] + [Category("ActorId Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Guid ActorId + { + get + { + return ((Guid)(base.GetValue(UpdateReferenceAttributeActivity.ActorIdProperty))); + } + set + { + base.SetValue(UpdateReferenceAttributeActivity.ActorIdProperty, value); + } + } + + public static DependencyProperty ResourceIdProperty = DependencyProperty.Register("ResourceId", typeof(Guid), typeof(UpdateReferenceAttributeActivity)); + + [Description("ResourceId")] + [Category("ResourceId Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Guid ResourceId + { + get + { + return ((Guid)(base.GetValue(UpdateReferenceAttributeActivity.ResourceIdProperty))); + } + set + { + base.SetValue(UpdateReferenceAttributeActivity.ResourceIdProperty, value); + } + } + + public static DependencyProperty ValuesProperty = DependencyProperty.Register("Values", typeof(Guid[]), typeof(UpdateReferenceAttributeActivity)); + + public static DependencyProperty AttributeNameProperty = DependencyProperty.Register("AttributeName", typeof(string), typeof(UpdateReferenceAttributeActivity)); + + [Description("AttributeName")] + [Category("AttributeName Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public string AttributeName + { + get + { + return ((string)(base.GetValue(UpdateReferenceAttributeActivity.AttributeNameProperty))); + } + set + { + base.SetValue(UpdateReferenceAttributeActivity.AttributeNameProperty, value); + } + } + + [Description("Values")] + [Category("Values Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Guid[] Values + { + get + { + return ((Guid[])(base.GetValue(UpdateReferenceAttributeActivity.ValuesProperty))); + } + set + { + base.SetValue(UpdateReferenceAttributeActivity.ValuesProperty, value); + } + } + + public static DependencyProperty UpdateModeProperty = DependencyProperty.Register("UpdateMode", typeof(Microsoft.ResourceManagement.WebServices.WSResourceManagement.UpdateMode), typeof(UpdateReferenceAttributeActivity)); + + [Description("UpdateMode")] + [Category("UpdateMode Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public UpdateMode UpdateMode + { + get + { + return ((Microsoft.ResourceManagement.WebServices.WSResourceManagement.UpdateMode)(base.GetValue(UpdateReferenceAttributeActivity.UpdateModeProperty))); + } + set + { + base.SetValue(UpdateReferenceAttributeActivity.UpdateModeProperty, value); + } + } + #endregion + + public UpdateReferenceAttributeActivity() + { + InitializeComponent(); + } + + private void PrepareUpdate_ExecuteCode(object sender, EventArgs e) + { + List tempParameters = new List(); + foreach (Guid guid in this.Values) + { + tempParameters.Add(new UpdateRequestParameter(this.AttributeName, this.UpdateMode, guid)); + } + + this.UpdateParameters = tempParameters.ToArray(); + } + + public UpdateRequestParameter[] UpdateParameters = null; + + private void AreValuesPresent(object sender, ConditionalEventArgs e) + { + if (this.Values != null && this.Values.Length > 0) + e.Result = true; + else + e.Result = false; + } + } +} \ No newline at end of file diff --git a/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/UpdateReferenceAttributesAsNeededActivity.cs b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/UpdateReferenceAttributesAsNeededActivity.cs new file mode 100644 index 0000000..6cd8ea8 --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/UpdateReferenceAttributesAsNeededActivity.cs @@ -0,0 +1,141 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Linq; +using System.Workflow.Activities; +using System.Workflow.ComponentModel; +using System.Workflow.ComponentModel.Design; + +namespace Granfeldt.FIM.ActivityLibrary +{ + [Designer(typeof(ActivityDesigner), typeof(IDesigner))] + public partial class UpdateReferenceAttributesAsNeededActivity: SequenceActivity + { + public UpdateReferenceAttributesAsNeededActivity() + { + InitializeComponent(); + } + + public static DependencyProperty ActorIdProperty = DependencyProperty.Register("ActorId", typeof(System.Guid), typeof(UpdateReferenceAttributesAsNeededActivity)); + + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + [Browsable(true)] + [Category("ActorId Category")] + public Guid ActorId + { + get + { + return ((System.Guid)(base.GetValue(UpdateReferenceAttributesAsNeededActivity.ActorIdProperty))); + } + set + { + base.SetValue(UpdateReferenceAttributesAsNeededActivity.ActorIdProperty, value); + } + } + + public static DependencyProperty ResourceIdProperty = DependencyProperty.Register("ResourceId", typeof(System.Guid), typeof(UpdateReferenceAttributesAsNeededActivity)); + + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + [Browsable(true)] + [Category("ResourceId Category")] + public Guid ResourceId + { + get + { + return ((System.Guid)(base.GetValue(UpdateReferenceAttributesAsNeededActivity.ResourceIdProperty))); + } + set + { + base.SetValue(UpdateReferenceAttributesAsNeededActivity.ResourceIdProperty, value); + } + } + + public static DependencyProperty UpdateModeProperty = DependencyProperty.Register("UpdateMode", typeof(Microsoft.ResourceManagement.WebServices.WSResourceManagement.UpdateMode), typeof(UpdateReferenceAttributesAsNeededActivity)); + + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + [Browsable(true)] + [Category("UpdateMode Category")] + public Microsoft.ResourceManagement.WebServices.WSResourceManagement.UpdateMode UpdateMode + { + get + { + return ((Microsoft.ResourceManagement.WebServices.WSResourceManagement.UpdateMode)(base.GetValue(UpdateReferenceAttributesAsNeededActivity.UpdateModeProperty))); + } + set + { + base.SetValue(UpdateReferenceAttributesAsNeededActivity.UpdateModeProperty, value); + } + } + + public static DependencyProperty ValuesProperty = DependencyProperty.Register("Values", typeof(System.Guid[]), typeof(UpdateReferenceAttributesAsNeededActivity)); + + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + [Browsable(true)] + [Category("Values Category")] + public Guid[] Values + { + get + { + return ((System.Guid[])(base.GetValue(UpdateReferenceAttributesAsNeededActivity.ValuesProperty))); + } + set + { + base.SetValue(UpdateReferenceAttributesAsNeededActivity.ValuesProperty, value); + } + } + + public static DependencyProperty AttributeNameProperty = DependencyProperty.Register("AttributeName", typeof(System.String), typeof(UpdateReferenceAttributesAsNeededActivity)); + + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + [Browsable(true)] + [Category("AttributeName Category")] + public String AttributeName + { + get + { + return ((string)(base.GetValue(UpdateReferenceAttributesAsNeededActivity.AttributeNameProperty))); + } + set + { + base.SetValue(UpdateReferenceAttributesAsNeededActivity.AttributeNameProperty, value); + } + } + + public Guid[] ValuesToSet = default(System.Guid[]); + + private void FindOutIfThereIsAPointInDoingAnything(object sender, ConditionalEventArgs e) + { + if(null==this.Values || this.Values.Length==0) + { + e.Result = false; + return; + } + switch (this.UpdateMode) + { + case Microsoft.ResourceManagement.WebServices.WSResourceManagement.UpdateMode.Insert: + this.ValuesToSet = this.Values.Except(this.CurrentValues).ToArray(); + e.Result = true; + break; + case Microsoft.ResourceManagement.WebServices.WSResourceManagement.UpdateMode.Modify: + if (this.CurrentValues.Except(this.Values).Count()>0 || + this.Values.Except(this.CurrentValues).Count()>0) + { + this.ValuesToSet = this.Values; + e.Result = true; + + } + else + { + e.Result = false; + } + break; + case Microsoft.ResourceManagement.WebServices.WSResourceManagement.UpdateMode.Remove: + this.ValuesToSet = this.Values.Intersect(this.CurrentValues).ToArray(); + e.Result = true; + break; + } + } + + public Guid[] CurrentValues = default(System.Guid[]); + } +} \ No newline at end of file diff --git a/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/UpdateReferenceAttributesAsNeededActivity.designer.cs b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/UpdateReferenceAttributesAsNeededActivity.designer.cs new file mode 100644 index 0000000..85c2412 --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Activity.AddBackReference/UpdateReferenceAttributesAsNeededActivity.designer.cs @@ -0,0 +1,102 @@ +using System.Workflow.Activities; + +namespace Granfeldt.FIM.ActivityLibrary +{ + public partial class UpdateReferenceAttributesAsNeededActivity + { + #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; + System.Workflow.ComponentModel.ActivityBind activitybind1 = new System.Workflow.ComponentModel.ActivityBind(); + System.Workflow.ComponentModel.ActivityBind activitybind2 = new System.Workflow.ComponentModel.ActivityBind(); + System.Workflow.ComponentModel.ActivityBind activitybind3 = new System.Workflow.ComponentModel.ActivityBind(); + System.Workflow.ComponentModel.ActivityBind activitybind4 = new System.Workflow.ComponentModel.ActivityBind(); + System.Workflow.ComponentModel.ActivityBind activitybind5 = new System.Workflow.ComponentModel.ActivityBind(); + System.Workflow.Activities.CodeCondition codecondition1 = new System.Workflow.Activities.CodeCondition(); + System.Workflow.ComponentModel.ActivityBind activitybind6 = new System.Workflow.ComponentModel.ActivityBind(); + System.Workflow.ComponentModel.ActivityBind activitybind7 = new System.Workflow.ComponentModel.ActivityBind(); + System.Workflow.ComponentModel.ActivityBind activitybind8 = new System.Workflow.ComponentModel.ActivityBind(); + System.Workflow.ComponentModel.ActivityBind activitybind9 = new System.Workflow.ComponentModel.ActivityBind(); + this.UpdateReferences = new UpdateReferenceAttributeActivity(); + this.NotAtAll = new System.Workflow.Activities.IfElseBranchActivity(); + this.Probably = new System.Workflow.Activities.IfElseBranchActivity(); + this.IsTherePointInDoingAnything = new System.Workflow.Activities.IfElseActivity(); + this.GetCurrentReferences = new Granfeldt.FIM.ActivityLibrary.GetReferenceValuesFromObjectActivity(); + // + // UpdateReferences + // + activitybind1.Name = "UpdateReferenceAttributesAsNeededActivity"; + activitybind1.Path = "ActorId"; + activitybind2.Name = "UpdateReferenceAttributesAsNeededActivity"; + activitybind2.Path = "AttributeName"; + this.UpdateReferences.Name = "UpdateReferences"; + activitybind3.Name = "UpdateReferenceAttributesAsNeededActivity"; + activitybind3.Path = "ResourceId"; + activitybind4.Name = "UpdateReferenceAttributesAsNeededActivity"; + activitybind4.Path = "UpdateMode"; + activitybind5.Name = "UpdateReferenceAttributesAsNeededActivity"; + activitybind5.Path = "ValuesToSet"; + this.UpdateReferences.SetBinding(UpdateReferenceAttributeActivity.ActorIdProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind1))); + this.UpdateReferences.SetBinding(UpdateReferenceAttributeActivity.ResourceIdProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind3))); + this.UpdateReferences.SetBinding(UpdateReferenceAttributeActivity.UpdateModeProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind4))); + this.UpdateReferences.SetBinding(UpdateReferenceAttributeActivity.ValuesProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind5))); + this.UpdateReferences.SetBinding(UpdateReferenceAttributeActivity.AttributeNameProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind2))); + // + // NotAtAll + // + this.NotAtAll.Name = "NotAtAll"; + // + // Probably + // + this.Probably.Activities.Add(this.UpdateReferences); + codecondition1.Condition += new System.EventHandler(this.FindOutIfThereIsAPointInDoingAnything); + this.Probably.Condition = codecondition1; + this.Probably.Name = "Probably"; + // + // IsTherePointInDoingAnything + // + this.IsTherePointInDoingAnything.Activities.Add(this.Probably); + this.IsTherePointInDoingAnything.Activities.Add(this.NotAtAll); + this.IsTherePointInDoingAnything.Name = "IsTherePointInDoingAnything"; + // + // GetCurrentReferences + // + activitybind6.Name = "UpdateReferenceAttributesAsNeededActivity"; + activitybind6.Path = "ActorId"; + activitybind7.Name = "UpdateReferenceAttributesAsNeededActivity"; + activitybind7.Path = "AttributeName"; + activitybind8.Name = "UpdateReferenceAttributesAsNeededActivity"; + activitybind8.Path = "CurrentValues"; + this.GetCurrentReferences.Name = "GetCurrentReferences"; + activitybind9.Name = "UpdateReferenceAttributesAsNeededActivity"; + activitybind9.Path = "ResourceId"; + this.GetCurrentReferences.SetBinding(Granfeldt.FIM.ActivityLibrary.GetReferenceValuesFromObjectActivity.ActorIdProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind6))); + this.GetCurrentReferences.SetBinding(Granfeldt.FIM.ActivityLibrary.GetReferenceValuesFromObjectActivity.AttributeNameProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind7))); + this.GetCurrentReferences.SetBinding(Granfeldt.FIM.ActivityLibrary.GetReferenceValuesFromObjectActivity.CurrentValuesProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind8))); + this.GetCurrentReferences.SetBinding(Granfeldt.FIM.ActivityLibrary.GetReferenceValuesFromObjectActivity.ObjectIDProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind9))); + // + // UpdateReferenceAttributesAsNeededActivity + // + this.Activities.Add(this.GetCurrentReferences); + this.Activities.Add(this.IsTherePointInDoingAnything); + this.Name = "UpdateReferenceAttributesAsNeededActivity"; + this.CanModifyActivities = false; + + } + + #endregion + + private GetReferenceValuesFromObjectActivity GetCurrentReferences; + private IfElseBranchActivity NotAtAll; + private IfElseBranchActivity Probably; + private IfElseActivity IsTherePointInDoingAnything; + private UpdateReferenceAttributeActivity UpdateReferences; + } +} \ No newline at end of file diff --git a/Granfeldt.FIM.ActivityLibrary/Activity.AddRemoveFromMultivalue/Activity.AddRemoveFromMultiValue.Designer.cs b/Granfeldt.FIM.ActivityLibrary/Activity.AddRemoveFromMultivalue/Activity.AddRemoveFromMultiValue.Designer.cs new file mode 100644 index 0000000..b46c0d8 --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Activity.AddRemoveFromMultivalue/Activity.AddRemoveFromMultiValue.Designer.cs @@ -0,0 +1,204 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Collections; +using System.Reflection; +using System.Workflow.ComponentModel; +using System.Workflow.ComponentModel.Design; +using System.Workflow.ComponentModel.Compiler; +using System.Workflow.ComponentModel.Serialization; +using System.Workflow.Runtime; +using System.Workflow.Activities; +using System.Workflow.Activities.Rules; + +namespace Granfeldt.FIM.ActivityLibrary +{ + public partial class AddRemoveFromMultiValueActivity + { + #region Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + [System.Diagnostics.DebuggerNonUserCode] + [System.CodeDom.Compiler.GeneratedCode("", "")] + private void InitializeComponent() + { + this.CanModifyActivities = true; + System.Workflow.Activities.CodeCondition codecondition1 = new System.Workflow.Activities.CodeCondition(); + System.Collections.Generic.List list_11 = new System.Collections.Generic.List(); + System.Workflow.ComponentModel.ActivityBind activitybind1 = new System.Workflow.ComponentModel.ActivityBind(); + System.Workflow.ComponentModel.ActivityBind activitybind2 = new System.Workflow.ComponentModel.ActivityBind(); + System.Workflow.ComponentModel.ActivityBind activitybind3 = new System.Workflow.ComponentModel.ActivityBind(); + System.Workflow.ComponentModel.ActivityBind activitybind4 = new System.Workflow.ComponentModel.ActivityBind(); + System.Workflow.ComponentModel.ActivityBind activitybind5 = new System.Workflow.ComponentModel.ActivityBind(); + this.LogException = new System.Workflow.Activities.CodeActivity(); + this.LogArgumentException = new System.Workflow.Activities.CodeActivity(); + this.faultHandlerGeneralException = new System.Workflow.ComponentModel.FaultHandlerActivity(); + this.faultHandlerArgumentException = new System.Workflow.ComponentModel.FaultHandlerActivity(); + this.UpdateMVOnTarget = new Granfeldt.FIM.ActivityLibrary.AddRemoveMultiValueActivityAsNeeded(); + this.faultHandlersActivity1 = new System.Workflow.ComponentModel.FaultHandlersActivity(); + this.LoopAndUpdateAllTargets = new System.Workflow.Activities.WhileActivity(); + this.Enumerate = new Granfeldt.FIM.ActivityLibrary.FindResourcesActivity(); + this.SetupVariablesActivity = new System.Workflow.Activities.CodeActivity(); + this.ResolveValueToAdd = new Microsoft.ResourceManagement.Workflow.Activities.ResolveGrammarActivity(); + this.ResolveLookupXPath = new Microsoft.ResourceManagement.Workflow.Activities.ResolveGrammarActivity(); + this.GetCurrentRequest = new Microsoft.ResourceManagement.Workflow.Activities.CurrentRequestActivity(); + // + // LogException + // + this.LogException.Name = "LogException"; + this.LogException.ExecuteCode += new System.EventHandler(this.LogException_ExecuteCode); + // + // LogArgumentException + // + this.LogArgumentException.Name = "LogArgumentException"; + this.LogArgumentException.ExecuteCode += new System.EventHandler(this.LogArgumentException_ExecuteCode); + // + // faultHandlerGeneralException + // + this.faultHandlerGeneralException.Activities.Add(this.LogException); + this.faultHandlerGeneralException.FaultType = typeof(System.Exception); + this.faultHandlerGeneralException.Name = "faultHandlerGeneralException"; + // + // faultHandlerArgumentException + // + this.faultHandlerArgumentException.Activities.Add(this.LogArgumentException); + this.faultHandlerArgumentException.FaultType = typeof(System.ArgumentException); + this.faultHandlerArgumentException.Name = "faultHandlerArgumentException"; + // + // UpdateMVOnTarget + // + this.UpdateMVOnTarget.Action = null; + this.UpdateMVOnTarget.Destination = null; + this.UpdateMVOnTarget.Name = "UpdateMVOnTarget"; + this.UpdateMVOnTarget.TargetIdToUpdate = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.UpdateMVOnTarget.TargetResource = null; + this.UpdateMVOnTarget.ValueToAddOrRemove = null; + // + // faultHandlersActivity1 + // + this.faultHandlersActivity1.Activities.Add(this.faultHandlerArgumentException); + this.faultHandlersActivity1.Activities.Add(this.faultHandlerGeneralException); + this.faultHandlersActivity1.Name = "faultHandlersActivity1"; + // + // LoopAndUpdateAllTargets + // + this.LoopAndUpdateAllTargets.Activities.Add(this.UpdateMVOnTarget); + codecondition1.Condition += new System.EventHandler(this.MoreTargetsToUpdate_Condition); + this.LoopAndUpdateAllTargets.Condition = codecondition1; + this.LoopAndUpdateAllTargets.Name = "LoopAndUpdateAllTargets"; + // + // Enumerate + // + this.Enumerate.ActorId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.Enumerate.Attributes = null; + this.Enumerate.EnumeratedResourceIDs = null; + this.Enumerate.EnumeratedResources = list_11; + this.Enumerate.Name = "Enumerate"; + this.Enumerate.PageSize = 0; + this.Enumerate.SortingAttributes = null; + this.Enumerate.TotalResultsCount = 0; + this.Enumerate.XPathFilter = null; + // + // SetupVariablesActivity + // + this.SetupVariablesActivity.Name = "SetupVariablesActivity"; + this.SetupVariablesActivity.ExecuteCode += new System.EventHandler(this.SetupVariablesActivity_ExecuteCode); + // + // ResolveValueToAdd + // + activitybind1.Name = "AddRemoveFromMultiValueActivity"; + activitybind1.Path = "ValueToAddRemove"; + this.ResolveValueToAdd.Name = "ResolveValueToAdd"; + activitybind2.Name = "AddRemoveFromMultiValueActivity"; + activitybind2.Path = "ValueToAddRemoveResolved"; + this.ResolveValueToAdd.WorkflowDictionaryKey = null; + this.ResolveValueToAdd.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.ResolveGrammarActivity.GrammarExpressionProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind1))); + this.ResolveValueToAdd.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.ResolveGrammarActivity.ResolvedExpressionProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind2))); + // + // ResolveLookupXPath + // + activitybind3.Name = "AddRemoveFromMultiValueActivity"; + activitybind3.Path = "LookupXPath"; + this.ResolveLookupXPath.Name = "ResolveLookupXPath"; + activitybind4.Name = "AddRemoveFromMultiValueActivity"; + activitybind4.Path = "ResolvedLookupXPath"; + this.ResolveLookupXPath.WorkflowDictionaryKey = null; + this.ResolveLookupXPath.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.ResolveGrammarActivity.GrammarExpressionProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind3))); + this.ResolveLookupXPath.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.ResolveGrammarActivity.ResolvedExpressionProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind4))); + // + // GetCurrentRequest + // + activitybind5.Name = "AddRemoveFromMultiValueActivity"; + activitybind5.Path = "CurrentRequest"; + this.GetCurrentRequest.Name = "GetCurrentRequest"; + this.GetCurrentRequest.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.CurrentRequestActivity.CurrentRequestProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind5))); + // + // AddRemoveFromMultiValueActivity + // + this.Activities.Add(this.GetCurrentRequest); + this.Activities.Add(this.ResolveLookupXPath); + this.Activities.Add(this.ResolveValueToAdd); + this.Activities.Add(this.SetupVariablesActivity); + this.Activities.Add(this.Enumerate); + this.Activities.Add(this.LoopAndUpdateAllTargets); + this.Activities.Add(this.faultHandlersActivity1); + this.Name = "AddRemoveFromMultiValueActivity"; + this.CanModifyActivities = false; + + } + + #endregion + + private CodeActivity LogException; + + private FaultHandlerActivity faultHandlerGeneralException; + + private CodeActivity LogArgumentException; + + private FaultHandlerActivity faultHandlerArgumentException; + + private FaultHandlersActivity faultHandlersActivity1; + + private Microsoft.ResourceManagement.Workflow.Activities.ResolveGrammarActivity ResolveValueToAdd; + + private AddRemoveMultiValueActivityAsNeeded UpdateMVOnTarget; + + private WhileActivity LoopAndUpdateAllTargets; + + private Microsoft.ResourceManagement.Workflow.Activities.CurrentRequestActivity GetCurrentRequest; + + private FindResourcesActivity Enumerate; + + private CodeActivity SetupVariablesActivity; + + private Microsoft.ResourceManagement.Workflow.Activities.ResolveGrammarActivity ResolveLookupXPath; + + + + + + + + + + + + + + + + + + + + + + + + + + } +} diff --git a/Granfeldt.FIM.ActivityLibrary/Activity.AddRemoveFromMultivalue/Activity.AddRemoveFromMultiValue.SettingsPart.cs b/Granfeldt.FIM.ActivityLibrary/Activity.AddRemoveFromMultivalue/Activity.AddRemoveFromMultiValue.SettingsPart.cs new file mode 100644 index 0000000..b1dbfd7 --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Activity.AddRemoveFromMultivalue/Activity.AddRemoveFromMultiValue.SettingsPart.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Web.UI.WebControls; +using System.Workflow.ComponentModel; +using Microsoft.IdentityManagement.WebUI.Controls; +using Microsoft.ResourceManagement.Workflow.Activities; + +namespace Granfeldt.FIM.ActivityLibrary.WebUIs +{ + class AddRemoveFromMultiValueActivitySettingsPart : BaseActivitySettingsPart + { + + const string LookupXPath = "TargetObjects"; + const string ValueToAddRemove = "ValueToAddRemove"; + const string MultivalueAttributeName = "TargetMultivalueAttributename"; + const string HandleDuplicates = "HandleDuplicates"; + const string Action = "Action"; + const string Actor = "Actor"; + + protected override void CreateChildControls() + { + Table layoutTable; + layoutTable = new Table(); + + // width is set to 100% of the control size + layoutTable.Width = Unit.Percentage(100.0); + layoutTable.BorderWidth = 0; + layoutTable.CellPadding = 2; + + // add a TableRow for each textbox in the UI + layoutTable.Rows.Add(this.AddTableRowTextBox("Target object(s) (XPath Filter):", "txt" + LookupXPath, 400, 1000, false, "")); + layoutTable.Rows.Add(this.AddTableRowTextBox("Value to add, i.e. [//Target/ObjectID]:", "txt" + ValueToAddRemove, 400, 100, false, "")); + layoutTable.Rows.Add(this.AddTableRowTextBox("Target multi-value attributename:", "txt" + MultivalueAttributeName, 400, 100, false, "")); + layoutTable.Rows.Add(this.AddAddRemoveDropDownList("Action:", "txt" + Action, 400, "Add")); + layoutTable.Rows.Add(this.AddCheckbox("Add/remove duplicates", "txt" + HandleDuplicates, false)); + layoutTable.Rows.Add(this.AddActorDropDownList("Actor (run as):", "txt" + Actor, 400, WellKnownGuids.FIMServiceAccount.ToString())); + this.Controls.Add(layoutTable); + base.CreateChildControls(); + } + + public override Activity GenerateActivityOnWorkflow(SequentialWorkflow workflow) + { + Debugging.Log("GenerateActivityOnWorkflow"); + if (!this.ValidateInputs()) + { + return null; + } + AddRemoveFromMultiValueActivity act = new AddRemoveFromMultiValueActivity(); + act.ValueToAddRemove = this.GetText("txt" + ValueToAddRemove); + act.LookupXPath = this.GetText("txt" + LookupXPath); + act.MultivalueAttributeName = this.GetText("txt" + MultivalueAttributeName); + act.Actor = this.GetActorDropDownList("txt" + Actor); + act.AddRemoveAction = this.GetAddRemoveDropDownList("txt" + Action); + return act; + } + + public override void LoadActivitySettings(Activity activity) + { + Debugging.Log("LoadActivitySettings"); + AddRemoveFromMultiValueActivity thisActivity = activity as AddRemoveFromMultiValueActivity; + if (thisActivity != null) + { + this.SetText("txt" + LookupXPath, thisActivity.LookupXPath); + this.SetText("txt" + ValueToAddRemove, thisActivity.ValueToAddRemove); + this.SetText("txt" + MultivalueAttributeName, thisActivity.MultivalueAttributeName); + this.SetActorDropDownList("txt" + Actor, thisActivity.Actor); + this.SetAddRemoveDropDownList("txt" + Action, thisActivity.AddRemoveAction); + } + } + + public override ActivitySettingsPartData PersistSettings() + { + Debugging.Log("PersistSettings"); + ActivitySettingsPartData data = new ActivitySettingsPartData(); + data[LookupXPath] = this.GetText("txt" + LookupXPath); + data[MultivalueAttributeName] = this.GetText("txt" + MultivalueAttributeName); + data[ValueToAddRemove] = this.GetText("txt" + ValueToAddRemove); + data[Actor] = this.GetActorDropDownList("txt" + Actor); + data[Action] = this.GetAddRemoveDropDownList("txt" + Action); + return data; + } + + public override void RestoreSettings(ActivitySettingsPartData data) + { + Debugging.Log("RestoreSettings"); + if (null != data) + { + this.SetText("txt" + LookupXPath, (string)data[LookupXPath]); + this.SetText("txt" + MultivalueAttributeName, (string)data[MultivalueAttributeName]); + this.SetText("txt" + ValueToAddRemove, (string)data[ValueToAddRemove]); + this.SetActorDropDownList("txt" + Actor, (string)data[Actor]); + this.SetAddRemoveDropDownList("txt" + Action, (string)data[Action]); + } + } + + public override void SwitchMode(ActivitySettingsPartMode mode) + { + Debugging.Log("SwitchMode"); + bool isDisabled = (mode != ActivitySettingsPartMode.Edit); + this.SetTextBoxReadOnlyOption("txt" + LookupXPath, isDisabled); + this.SetTextBoxReadOnlyOption("txt" + MultivalueAttributeName, isDisabled); + this.SetTextBoxReadOnlyOption("txt" + ValueToAddRemove, isDisabled); + this.SetDropDownListDisabled("txt" + Actor, isDisabled); + this.SetDropDownListDisabled("txt" + Action, isDisabled); + } + + public override string Title + { + get { return "Add or Remove to/from multi-value"; } + } + + public override bool ValidateInputs() + { + Debugging.Log("ValidateInputs"); + return true; + } + } +} diff --git a/Granfeldt.FIM.ActivityLibrary/Activity.AddRemoveFromMultivalue/Activity.AddRemoveFromMultiValue.cs b/Granfeldt.FIM.ActivityLibrary/Activity.AddRemoveFromMultivalue/Activity.AddRemoveFromMultiValue.cs new file mode 100644 index 0000000..381c7c7 --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Activity.AddRemoveFromMultivalue/Activity.AddRemoveFromMultiValue.cs @@ -0,0 +1,230 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Collections; +using System.Linq; +using System.Workflow.ComponentModel; +using System.Workflow.ComponentModel.Design; +using System.Workflow.ComponentModel.Compiler; +using System.Workflow.ComponentModel.Serialization; +using System.Workflow.Runtime; +using System.Workflow.Activities; +using System.Workflow.Activities.Rules; +using Microsoft.ResourceManagement.WebServices.WSResourceManagement; + +namespace Granfeldt.FIM.ActivityLibrary +{ + public partial class AddRemoveFromMultiValueActivity : SequenceActivity + { + + #region Properties + + public AddRemoveFromMultiValueActivity() + { + InitializeComponent(); + } + + public static DependencyProperty HandleDuplicateProperty = DependencyProperty.Register("HandleDuplicate", typeof(string), typeof(AddRemoveFromMultiValueActivity)); + [Description("HandleDuplicate")] + [Category("HandleDuplicate Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public string HandleDuplicate + { + get + { + return ((string)(base.GetValue(AddRemoveFromMultiValueActivity.HandleDuplicateProperty))); + } + set + { + base.SetValue(AddRemoveFromMultiValueActivity.HandleDuplicateProperty, value); + } + } + + public static DependencyProperty ActorProperty = DependencyProperty.Register("Actor", typeof(string), typeof(AddRemoveFromMultiValueActivity)); + [Description("Actor")] + [Category("Actor Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public string Actor + { + get + { + return ((string)(base.GetValue(AddRemoveFromMultiValueActivity.ActorProperty))); + } + set + { + base.SetValue(AddRemoveFromMultiValueActivity.ActorProperty, value); + } + } + + public static DependencyProperty LookupXPathProperty = DependencyProperty.Register("LookupXPath", typeof(System.String), typeof(AddRemoveFromMultiValueActivity)); + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] + [BrowsableAttribute(true)] + [CategoryAttribute("Misc")] + public String LookupXPath + { + get + { + return ((string)(base.GetValue(LookupXPathProperty))); + } + set + { + base.SetValue(LookupXPathProperty, value); + } + } + + public static DependencyProperty ResolvedLookupXPathProperty = DependencyProperty.Register("ResolvedLookupXPath", typeof(System.String), typeof(AddRemoveFromMultiValueActivity)); + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] + [BrowsableAttribute(true)] + [CategoryAttribute("Misc")] + public String ResolvedLookupXPath + { + get + { + return ((string)(base.GetValue(AddRemoveFromMultiValueActivity.ResolvedLookupXPathProperty))); + } + set + { + base.SetValue(AddRemoveFromMultiValueActivity.ResolvedLookupXPathProperty, value); + } + } + + public static DependencyProperty ValueToAddRemoveProperty = DependencyProperty.Register("ValueToAddRemove", typeof(string), typeof(AddRemoveFromMultiValueActivity)); + [Description("ValueToAddRemove")] + [Category("ValueToAddRemove Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public string ValueToAddRemove + { + get + { + return ((string)(base.GetValue(AddRemoveFromMultiValueActivity.ValueToAddRemoveProperty))); + } + set + { + base.SetValue(AddRemoveFromMultiValueActivity.ValueToAddRemoveProperty, value); + } + } + + public static DependencyProperty MultivalueAttributeNameProperty = DependencyProperty.Register("MultivalueAttributeName", typeof(string), typeof(AddRemoveFromMultiValueActivity)); + [Description("MultivalueAttributeName")] + [Category("MultivalueAttributeName Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public string MultivalueAttributeName + { + get + { + return ((string)(base.GetValue(AddRemoveFromMultiValueActivity.MultivalueAttributeNameProperty))); + } + set + { + base.SetValue(AddRemoveFromMultiValueActivity.MultivalueAttributeNameProperty, value); + } + } + + public static DependencyProperty AddRemoveActionProperty = DependencyProperty.Register("AddRemoveAction", typeof(string), typeof(AddRemoveFromMultiValueActivity)); + [Description("AddRemoveAction")] + [Category("AddRemoveAction Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public string AddRemoveAction + { + get + { + return ((string)(base.GetValue(AddRemoveFromMultiValueActivity.AddRemoveActionProperty))); + } + set + { + base.SetValue(AddRemoveFromMultiValueActivity.AddRemoveActionProperty, value); + } + } + + + public static DependencyProperty CurrentRequestProperty = DependencyProperty.Register("CurrentRequest", typeof(Microsoft.ResourceManagement.WebServices.WSResourceManagement.RequestType), typeof(AddRemoveFromMultiValueActivity)); + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] + [BrowsableAttribute(true)] + [CategoryAttribute("Misc")] + public RequestType CurrentRequest + { + get + { + return ((Microsoft.ResourceManagement.WebServices.WSResourceManagement.RequestType)(base.GetValue(CurrentRequestProperty))); + } + set + { + base.SetValue(CurrentRequestProperty, value); + } + } + + #endregion + + private void SetupVariablesActivity_ExecuteCode(object sender, EventArgs e) + { + foreach (CreateRequestParameter u in this.CurrentRequest.ParseParameters()) + { + } + + Debugging.Log("Enter SetupVariablesActivity_ExecuteCode"); + Enumerate.ActorId = new Guid(this.Actor); + Debugging.Log("XPath (resolved)", this.ResolvedLookupXPath); + Enumerate.XPathFilter = this.ResolvedLookupXPath; + Enumerate.Attributes = new string[] { this.MultivalueAttributeName }; + Enumerate.PageSize = 100; + Debugging.Log("Leave SetupVariablesActivity_ExecuteCode"); + } + + private void MoreTargetsToUpdate_Condition(object sender, ConditionalEventArgs e) + { + Debugging.Log("Enter SetupVariablesActivity_ExecuteCode"); + // return true if there are any more source values to resolve + e.Result = Enumerate.EnumeratedResources != null ? Enumerate.EnumeratedResources.Count() > 0 : false; + + if (e.Result) + { + Debugging.Log("Update target(s) left", Enumerate.EnumeratedResources.Count()); + ResourceType resource = Enumerate.EnumeratedResources[0]; + Enumerate.EnumeratedResources.RemoveAt(0); + + UpdateMVOnTarget.Action = this.AddRemoveAction; + UpdateMVOnTarget.Destination = this.MultivalueAttributeName; + UpdateMVOnTarget.ValueToAddOrRemove = this.ValueToAddRemoveResolved; + UpdateMVOnTarget.TargetIdToUpdate = resource.ObjectID.GetGuid(); + } + else + { + Debugging.Log("No more source values to resolve"); + } + } + + public static DependencyProperty ValueToAddRemoveResolvedProperty = DependencyProperty.Register("ValueToAddRemoveResolved", typeof(object), typeof(Granfeldt.FIM.ActivityLibrary.AddRemoveFromMultiValueActivity)); + + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] + [BrowsableAttribute(true)] + [CategoryAttribute("Misc")] + public String ValueToAddRemoveResolved + { + get + { + return ((string)(base.GetValue(Granfeldt.FIM.ActivityLibrary.AddRemoveFromMultiValueActivity.ValueToAddRemoveResolvedProperty))); + } + set + { + base.SetValue(Granfeldt.FIM.ActivityLibrary.AddRemoveFromMultiValueActivity.ValueToAddRemoveResolvedProperty, value); + } + } + + private void LogArgumentException_ExecuteCode(object sender, EventArgs e) + { + Debugging.Log(sender.ToString()); + Debugging.Log(faultHandlerArgumentException.Fault); + } + + private void LogException_ExecuteCode(object sender, EventArgs e) + { + Debugging.Log(sender.ToString()); + Debugging.Log(faultHandlerGeneralException.Fault); + } + } +} diff --git a/Granfeldt.FIM.ActivityLibrary/Activity.ClearSingleValueAttribute/Activity.ClearSingleValuedAttribute.Designer.cs b/Granfeldt.FIM.ActivityLibrary/Activity.ClearSingleValueAttribute/Activity.ClearSingleValuedAttribute.Designer.cs new file mode 100644 index 0000000..1d09bda --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Activity.ClearSingleValueAttribute/Activity.ClearSingleValuedAttribute.Designer.cs @@ -0,0 +1,133 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Collections; +using System.Drawing; +using System.Reflection; +using System.Workflow.ComponentModel; +using System.Workflow.ComponentModel.Design; +using System.Workflow.ComponentModel.Compiler; +using System.Workflow.ComponentModel.Serialization; +using System.Workflow.Runtime; +using System.Workflow.Activities; +using System.Workflow.Activities.Rules; + +namespace Granfeldt.FIM.ActivityLibrary +{ + public partial class ClearSingleValuedAttributeActivity + { + #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; + System.Workflow.Activities.CodeCondition codecondition1 = new System.Workflow.Activities.CodeCondition(); + System.Workflow.ComponentModel.ActivityBind activitybind1 = new System.Workflow.ComponentModel.ActivityBind(); + this.UpdateResource = new Microsoft.ResourceManagement.Workflow.Activities.UpdateResourceActivity(); + this.NoActionNeeded = new System.Workflow.Activities.IfElseBranchActivity(); + this.ThereWasValue = new System.Workflow.Activities.IfElseBranchActivity(); + this.EndGracefully = new System.Workflow.Activities.CodeActivity(); + this.IsRemovalNeeded = new System.Workflow.Activities.IfElseActivity(); + this.ReadResource = new Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity(); + this.PrepareReading = new System.Workflow.Activities.CodeActivity(); + this.GetCurrentRequest = new Microsoft.ResourceManagement.Workflow.Activities.CurrentRequestActivity(); + // + // UpdateResource + // + this.UpdateResource.ActorId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.UpdateResource.ApplyAuthorizationPolicy = false; + this.UpdateResource.Name = "UpdateResource"; + this.UpdateResource.ResourceId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.UpdateResource.UpdateParameters = null; + // + // NoActionNeeded + // + this.NoActionNeeded.Name = "NoActionNeeded"; + // + // ThereWasValue + // + this.ThereWasValue.Activities.Add(this.UpdateResource); + codecondition1.Condition += new System.EventHandler(this.ThereWasValue_Condition); + this.ThereWasValue.Condition = codecondition1; + this.ThereWasValue.Name = "ThereWasValue"; + // + // EndGracefully + // + this.EndGracefully.Name = "EndGracefully"; + this.EndGracefully.ExecuteCode += new System.EventHandler(this.EndGracefully_ExecuteCode); + // + // IsRemovalNeeded + // + this.IsRemovalNeeded.Activities.Add(this.ThereWasValue); + this.IsRemovalNeeded.Activities.Add(this.NoActionNeeded); + this.IsRemovalNeeded.Name = "IsRemovalNeeded"; + // + // ReadResource + // + this.ReadResource.ActorId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.ReadResource.Name = "ReadResource"; + this.ReadResource.Resource = null; + this.ReadResource.ResourceId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.ReadResource.SelectionAttributes = null; + // + // PrepareReading + // + this.PrepareReading.Name = "PrepareReading"; + this.PrepareReading.ExecuteCode += new System.EventHandler(this.PrepareReading_ExecuteCode); + // + // GetCurrentRequest + // + activitybind1.Name = "ClearSingleValuedAttributeActivity"; + activitybind1.Path = "CurrentRequest"; + this.GetCurrentRequest.Name = "GetCurrentRequest"; + this.GetCurrentRequest.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.CurrentRequestActivity.CurrentRequestProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind1))); + // + // ClearSingleValuedAttributeActivity + // + this.Activities.Add(this.GetCurrentRequest); + this.Activities.Add(this.PrepareReading); + this.Activities.Add(this.ReadResource); + this.Activities.Add(this.IsRemovalNeeded); + this.Activities.Add(this.EndGracefully); + this.Name = "ClearSingleValuedAttributeActivity"; + this.CanModifyActivities = false; + + } + + + + + + + + + + + + + + + + + + + + + + #endregion + + private Microsoft.ResourceManagement.Workflow.Activities.CurrentRequestActivity GetCurrentRequest; + private CodeActivity EndGracefully; + private Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity ReadResource; + private Microsoft.ResourceManagement.Workflow.Activities.UpdateResourceActivity UpdateResource; + private IfElseBranchActivity ThereWasValue; + private IfElseActivity IsRemovalNeeded; + private IfElseBranchActivity NoActionNeeded; + private CodeActivity PrepareReading; + } +} diff --git a/Granfeldt.FIM.ActivityLibrary/Activity.ClearSingleValueAttribute/Activity.ClearSingleValuedAttribute.cs b/Granfeldt.FIM.ActivityLibrary/Activity.ClearSingleValueAttribute/Activity.ClearSingleValuedAttribute.cs new file mode 100644 index 0000000..dee99fe --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Activity.ClearSingleValueAttribute/Activity.ClearSingleValuedAttribute.cs @@ -0,0 +1,180 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Collections; +using System.Drawing; +using System.Linq; +using System.Workflow.ComponentModel; +using System.Workflow.ComponentModel.Design; +using System.Workflow.ComponentModel.Compiler; +using System.Workflow.ComponentModel.Serialization; +using System.Workflow.Runtime; +using System.Workflow.Activities; +using System.Workflow.Activities.Rules; +using Microsoft.ResourceManagement.Workflow.Activities; +using Microsoft.ResourceManagement.WebServices.WSResourceManagement; + +namespace Granfeldt.FIM.ActivityLibrary +{ + + public partial class ClearSingleValuedAttributeActivity : SequenceActivity + { + + #region Properties + + public static DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(System.String), typeof(ClearSingleValuedAttributeActivity)); + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] + [BrowsableAttribute(true)] + [CategoryAttribute("Misc")] + public String Title + { + get + { + return ((string)(base.GetValue(TitleProperty))); + } + set + { + base.SetValue(TitleProperty, value); + } + } + + public static DependencyProperty CurrentRequestProperty = DependencyProperty.Register("CurrentRequest", typeof(Microsoft.ResourceManagement.WebServices.WSResourceManagement.RequestType), typeof(ClearSingleValuedAttributeActivity)); + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] + [BrowsableAttribute(true)] + [CategoryAttribute("Misc")] + public Microsoft.ResourceManagement.WebServices.WSResourceManagement.RequestType CurrentRequest + { + get + { + return ((Microsoft.ResourceManagement.WebServices.WSResourceManagement.RequestType)(base.GetValue(CurrentRequestProperty))); + } + set + { + base.SetValue(CurrentRequestProperty, value); + } + } + + public static DependencyProperty AttributeNameProperty = DependencyProperty.Register("AttributeName", typeof(string), typeof(ClearSingleValuedAttributeActivity)); + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + [Category("Properties")] + public string AttributeName + { + get + { + return (string)base.GetValue(AttributeNameProperty); + } + set + { + base.SetValue(AttributeNameProperty, value); + } + } + + public static DependencyProperty TargetIdProperty = DependencyProperty.Register("TargetId", typeof(Guid), typeof(ClearSingleValuedAttributeActivity)); + [Description("TargetId")] + [Category("TargetId Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Guid TargetId + { + get + { + return ((Guid)(base.GetValue(ClearSingleValuedAttributeActivity.TargetIdProperty))); + } + set + { + base.SetValue(ClearSingleValuedAttributeActivity.TargetIdProperty, value); + } + } + + #endregion + + public ClearSingleValuedAttributeActivity() + { + InitializeComponent(); + } + + void ActivityStatus(object sender, ActivityExecutionStatusChangedEventArgs e) + { + Tracer.TraceInformation("execution-status name: {0}, status: {1}, result: {2}", e.Activity.Name, e.ExecutionStatus, e.ExecutionResult); + } + + private void PrepareReading_ExecuteCode(object sender, EventArgs e) + { + Tracer.Enter("preparereading_executecode"); + try + { + ReadResource.ActorId = WellKnownGuids.FIMServiceAccount; + Tracer.TraceInformation("actor-objectid: {0}", ReadResource.ActorId); + ReadResource.ResourceId = CurrentRequest.Target.GetGuid(); + Tracer.TraceInformation("target-objectid: {0}", ReadResource.ResourceId); + ReadResource.SelectionAttributes = new string[] { this.AttributeName, "DisplayName" }; + Tracer.TraceInformation("attribute: {0}", ReadResource.SelectionAttributes.FirstOrDefault()); + + ReadResource.Executing += new System.EventHandler(ActivityStatus); + ReadResource.Faulting += new System.EventHandler(ActivityStatus); + ReadResource.StatusChanged += new System.EventHandler(ActivityStatus); + ReadResource.Canceling += new System.EventHandler(ActivityStatus); + ReadResource.Compensating += new System.EventHandler(ActivityStatus); + ReadResource.Closed += new System.EventHandler(ActivityStatus); + } + catch (Exception ex) + { + Tracer.TraceError("preparereading_executecode", ex); + } + Tracer.Exit("preparereading_executecode"); + } + + private void ThereWasValue_Condition(object sender, ConditionalEventArgs e) + { + try + { + Tracer.Enter("therewasvalue_condition"); + object displayName = ReadResource.Resource["DisplayName"]; + object myValue = ReadResource.Resource[this.AttributeName]; + Tracer.TraceInformation("target-displayname {0}", displayName); + if (null != myValue) + { + Tracer.TraceInformation("current-value: {0}", ReadResource.Resource[this.AttributeName]); + UpdateResource.ActorId = WellKnownGuids.FIMServiceAccount; + Tracer.TraceInformation("actor-objectid: {0}", UpdateResource.ActorId); + UpdateResource.ResourceId = CurrentRequest.Target.GetGuid(); + Tracer.TraceInformation("target-objectid: {0}", UpdateResource.ResourceId); + UpdateRequestParameter[] UpdateParameters = new UpdateRequestParameter[] { + new UpdateRequestParameter( + this.AttributeName, + UpdateMode.Remove, + myValue)}; + UpdateResource.UpdateParameters = UpdateParameters; + + UpdateResource.Executing += new System.EventHandler(ActivityStatus); + UpdateResource.Faulting += new System.EventHandler(ActivityStatus); + UpdateResource.StatusChanged += new System.EventHandler(ActivityStatus); + UpdateResource.Canceling += new System.EventHandler(ActivityStatus); + UpdateResource.Compensating += new System.EventHandler(ActivityStatus); + UpdateResource.Closed += new System.EventHandler(ActivityStatus); + + e.Result = true; + } + else + { + Tracer.TraceInformation("no-current-value-to-remove"); + e.Result = false; + } + } + catch (Exception ex) + { + Tracer.TraceError("therewasvalue_condition'", ex); + } + Tracer.Exit("therewasvalue_condition"); + } + + private void EndGracefully_ExecuteCode(object sender, EventArgs e) + { + Tracer.TraceInformation("done"); + } + + + } + +} diff --git a/Granfeldt.FIM.ActivityLibrary/Activity.ClearSingleValueAttribute/ClearSingleValuedAttributeActivitySettingsPart.cs b/Granfeldt.FIM.ActivityLibrary/Activity.ClearSingleValueAttribute/ClearSingleValuedAttributeActivitySettingsPart.cs new file mode 100644 index 0000000..26445a9 --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Activity.ClearSingleValueAttribute/ClearSingleValuedAttributeActivitySettingsPart.cs @@ -0,0 +1,182 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.Text; +using System.Web.UI.WebControls; +using System.Workflow.ComponentModel; +using Microsoft.IdentityManagement.WebUI.Controls; +using Microsoft.ResourceManagement.Workflow.Activities; + +namespace Granfeldt.FIM.ActivityLibrary.WebUIs +{ + + class ClearSingleValuedAttributeActivitySettingsPart : ActivitySettingsPart + { + + /// + /// Creates a Table that contains the controls used by the activity UI + /// in the Workflow Designer of the FIM portal. Adds that Table to the + /// collection of Controls that defines each activity that can be selected + /// in the Workflow Designer of the FIM Portal. Calls the base class of + /// ActivitySettingsPart to render the controls in the UI. + /// + protected override void CreateChildControls() + { + Table controlLayoutTable; + controlLayoutTable = new Table(); + + //Width is set to 100% of the control size + controlLayoutTable.Width = Unit.Percentage(100.0); + controlLayoutTable.BorderWidth = 0; + controlLayoutTable.CellPadding = 2; + //Add a TableRow for each textbox in the UI + controlLayoutTable.Rows.Add(this.AddTableRowTextBox("Title:", "txtTitle", 400, 100, false, "")); + controlLayoutTable.Rows.Add(this.AddTableRowTextBox("Attribute:", "txtDestination", 400, 100, false, "")); + this.Controls.Add(controlLayoutTable); + + base.CreateChildControls(); + } + + #region Utility Functions + + //Create a TableRow that contains a label and a textbox. + private TableRow AddTableRowTextBox(String labelText, String controlID, int width, int maxLength, Boolean multiLine, String defaultValue) + { + TableRow row = new TableRow(); + TableCell labelCell = new TableCell(); + TableCell controlCell = new TableCell(); + Label oLabel = new Label(); + TextBox oText = new TextBox(); + + oLabel.Text = labelText; + oLabel.CssClass = base.LabelCssClass; + labelCell.Controls.Add(oLabel); + oText.ID = controlID; + oText.CssClass = base.TextBoxCssClass; + oText.Text = defaultValue; + oText.MaxLength = maxLength; + oText.Width = width; + if (multiLine) + { + oText.TextMode = TextBoxMode.MultiLine; + oText.Rows = System.Math.Min(6, (maxLength + 60) / 60); + oText.Wrap = true; + } + controlCell.Controls.Add(oText); + row.Cells.Add(labelCell); + row.Cells.Add(controlCell); + return row; + } + + string GetText(string textBoxID) + { + TextBox textBox = (TextBox)this.FindControl(textBoxID); + return textBox.Text ?? String.Empty; + } + void SetText(string textBoxID, string text) + { + TextBox textBox = (TextBox)this.FindControl(textBoxID); + if (textBox != null) + textBox.Text = text; + else + textBox.Text = ""; + } + + //Set the text box to read mode or read/write mode + void SetTextBoxReadOnlyOption(string textBoxID, bool readOnly) + { + TextBox textBox = (TextBox)this.FindControl(textBoxID); + textBox.ReadOnly = readOnly; + } + #endregion + + /// + /// Called when a user clicks the Save button in the Workflow Designer. + /// Returns an instance of the RequestLoggingActivity class that + /// has its properties set to the values entered into the text box controls + /// used in the UI of the activity. + /// + public override Activity GenerateActivityOnWorkflow(SequentialWorkflow workflow) + { + if (!this.ValidateInputs()) + { + return null; + } + ClearSingleValuedAttributeActivity ThisActivity = new ClearSingleValuedAttributeActivity(); + ThisActivity.Title = this.GetText("txtTitle"); + ThisActivity.AttributeName = this.GetText("txtDestination"); + return ThisActivity; + } + + public override void LoadActivitySettings(Activity activity) + { + ClearSingleValuedAttributeActivity ThisActivity = activity as ClearSingleValuedAttributeActivity; + if (ThisActivity != null) + { + this.SetText("txtTitle", ThisActivity.Title); + this.SetText("txtDestination", ThisActivity.AttributeName); + } + } + + /// + /// Saves the activity settings. + /// + public override ActivitySettingsPartData PersistSettings() + { + ActivitySettingsPartData data = new ActivitySettingsPartData(); + data["Title"] = this.GetText("txtTitle"); + data["Attribute"] = this.GetText("txtDestination"); + return data; + } + + /// + /// Restores the activity settings in the UI + /// + public override void RestoreSettings(ActivitySettingsPartData data) + { + if (null != data) + { + this.SetText("txtTitle", (string)data["Title"]); + this.SetText("txtDestination", (string)data["Attribute"]); + } + } + + /// + /// Switches the activity between read only and read/write mode + /// + public override void SwitchMode(ActivitySettingsPartMode mode) + { + bool readOnly = (mode == ActivitySettingsPartMode.View); + this.SetTextBoxReadOnlyOption("txtTitle", readOnly); + this.SetTextBoxReadOnlyOption("txtDestination", readOnly); + } + + /// + /// Returns the activity name. + /// + public override string Title + { + get + { + return string.Format("Clear single-valued attribute: {0}", this.GetText("txtTitle")); + } + } + + /// + /// In general, this method should be used to validate information entered + /// by the user when the activity is added to a workflow in the Workflow + /// Designer. + /// We could add code to verify that the log file path already exists on + /// the server that is hosting the FIM Portal and check that the activity + /// has permission to write to that location. However, the code + /// would only check if the log file path exists when the + /// activity is added to a workflow in the workflow designer. This class + /// will not be used when the activity is actually run. + /// For this activity we will just return true. + /// + public override bool ValidateInputs() + { + return true; + } + } +} diff --git a/Granfeldt.FIM.ActivityLibrary/Activity.CodeRun/Activity.CodeRun.cs b/Granfeldt.FIM.ActivityLibrary/Activity.CodeRun/Activity.CodeRun.cs index 6335e96..1469e0c 100644 --- a/Granfeldt.FIM.ActivityLibrary/Activity.CodeRun/Activity.CodeRun.cs +++ b/Granfeldt.FIM.ActivityLibrary/Activity.CodeRun/Activity.CodeRun.cs @@ -5,6 +5,8 @@ // due to clashes with built-in naming convention // January 18, 2013 | Soren Granfeldt // - changed update to use helper update activity +// December 16, 2015 | soren granfeldt +// - changed logging to tuse tracer using System; using System.CodeDom.Compiler; @@ -41,7 +43,7 @@ namespace Granfeldt.FIM.ActivityLibrary { get { - return ((Microsoft.ResourceManagement.WebServices.WSResourceManagement.ResourceType)(base.GetValue(Granfeldt.FIM.ActivityLibrary.CodeRunActivity.TargetResourceProperty))); + return ((ResourceType)(base.GetValue(Granfeldt.FIM.ActivityLibrary.CodeRunActivity.TargetResourceProperty))); } set { @@ -187,19 +189,19 @@ namespace Granfeldt.FIM.ActivityLibrary private void MoreParametersToResolve_Condition(object sender, ConditionalEventArgs e) { - Debugging.Log("Activity initialized"); + Tracer.Enter("Activity initialized"); // we need to convert the string array to a list to // be able to remove values if (UnresolvedParameters == null) { UnresolvedParameters = this.Parameters.ToList(); - Debugging.Log("Resolving parameters"); + Tracer.TraceInformation("Resolving parameters"); } e.Result = false; if (UnresolvedParameters.Count > 0) { this.ResolveParameterValue.GrammarExpression = UnresolvedParameters[0]; - Debugging.Log("Resolving", UnresolvedParameters[0]); + Tracer.TraceInformation("Resolving {0}", UnresolvedParameters[0]); UnresolvedParameters.RemoveAt(0); e.Result = true; } @@ -208,15 +210,15 @@ namespace Granfeldt.FIM.ActivityLibrary private void SaveResolvedValue_ExecuteCode(object sender, EventArgs e) { ResolvedParameters.Add(HttpUtility.HtmlDecode(this.ResolveParameterValue.ResolvedExpression)); - Debugging.Log("Resolved to", HttpUtility.HtmlDecode(this.ResolveParameterValue.ResolvedExpression)); + Tracer.TraceInformation("Resolved to {0}", HttpUtility.HtmlDecode(this.ResolveParameterValue.ResolvedExpression)); } private void NonExistingGrammarException_ExecuteCode(object sender, EventArgs e) { - // if we get here, the resolve has failed. If the value that we're - // trying to resolve doesn't exist, we also get here. We - // assume that there is no value and set value to null - Debugging.Log("Missing value or invalid XPath reference (returning [null])", this.ResolveParameterValue.GrammarExpression); + // if we get here, the resolve has failed. If the value that we're + // trying to resolve doesn't exist, we also get here. We + // assume that there is no value and set value to null + Tracer.TraceError("Missing value or invalid XPath reference (returning [null]) {0}", this.ResolveParameterValue.GrammarExpression); ResolvedParameters.Add(null); } @@ -246,7 +248,7 @@ namespace Granfeldt.FIM.ActivityLibrary { compileErrors.AppendFormat("Compile Error: {0} in Ln {2} Col {3}-{1}\r\n", ce.ErrorNumber, ce.ErrorText, ce.Line, ce.Column); } - Debugging.Log(new Exception("Couldn't compile\r\n" + compileErrors)); + Tracer.TraceError("Couldn't compile {0}\r\n" + compileErrors); } Assembly assembly = cr.CompiledAssembly; compiled = assembly.CreateInstance("FIMDynamicClass"); @@ -256,18 +258,18 @@ namespace Granfeldt.FIM.ActivityLibrary { if (compiled == null) { - Debugging.Log(new NullReferenceException("Code must contain a class named FIMDynamicClass and that class must contain a method called FIMDynamicFunction")); + Tracer.TraceError("Code must contain a class named FIMDynamicClass and that class must contain a method called FIMDynamicFunction"); } - Debugging.Log("Parameter count", ResolvedParameters.Count); + Tracer.TraceInformation("Parameter count {0}", ResolvedParameters.Count); foreach (object param in ResolvedParameters) { - Debugging.Log("Adding parameter", param); + Tracer.TraceInformation("Adding parameter {0}", param); } MethodInfo mi = compiled.GetType().GetMethod("FIMDynamicFunction"); - Debugging.Log("Executing code"); + Tracer.TraceInformation("Executing code"); codeReturnValue = mi.Invoke(compiled, ResolvedParameters.ToArray()); - Debugging.Log("Code executed"); - Debugging.Log("Code return value", codeReturnValue); + Tracer.TraceInformation("Code executed"); + Tracer.TraceInformation("Code return value {0}", codeReturnValue); } private void ShouldUpdateTarget_Condition(object sender, ConditionalEventArgs e) @@ -275,7 +277,9 @@ namespace Granfeldt.FIM.ActivityLibrary // try to get parent workflow. if (!SequentialWorkflow.TryGetContainingWorkflow(this, out containingWorkflow)) { - throw new InvalidOperationException("Could not get parent workflow"); + string errorMessage = "Could not get parent workflow"; + Tracer.TraceError(errorMessage); + throw new InvalidOperationException(errorMessage); } StringUtilities.ExtractWorkflowExpression(this.Destination, out destinationObject, out destinationAttribute); @@ -300,7 +304,7 @@ namespace Granfeldt.FIM.ActivityLibrary } else { - Debugging.Log(new Exception("Could not resolved destination. Please specify as [//Target/Attribute] or [//WorkflowData/Parameter]")); + Tracer.TraceError("Could not resolved destination. Please specify as [//Target/Attribute] or [//WorkflowData/Parameter]"); } } @@ -311,12 +315,12 @@ namespace Granfeldt.FIM.ActivityLibrary // assume that there is no value and set source value to null // which effectively results in a 'Delete' operation on // the target attribute value (if present) - Debugging.Log("Error: Argument Exception"); + Tracer.TraceError("Error: Argument Exception"); } private void ExitGracefully_ExecuteCode(object sender, EventArgs e) { - Debugging.Log("Activity exited"); + Tracer.TraceInformation("Activity exited"); } } } diff --git a/Granfeldt.FIM.ActivityLibrary/Base/Base.ActivitySettings/Base.ActivitySettings.cs b/Granfeldt.FIM.ActivityLibrary/Base/Base.ActivitySettings/Base.ActivitySettings.cs index 489367c..eeb3d65 100644 --- a/Granfeldt.FIM.ActivityLibrary/Base/Base.ActivitySettings/Base.ActivitySettings.cs +++ b/Granfeldt.FIM.ActivityLibrary/Base/Base.ActivitySettings/Base.ActivitySettings.cs @@ -12,11 +12,6 @@ namespace Granfeldt.FIM.ActivityLibrary class BaseActivitySettingsPart : ActivitySettingsPart { - #region Utility Functions - - /// - /// Create a TableRow that contains a label and a textbox. - /// protected TableRow AddTableRowTextBox(String labelText, String controlID, int width, int maxLength, Boolean multiLine, String defaultValue) { TableRow row = new TableRow(); @@ -45,8 +40,60 @@ namespace Granfeldt.FIM.ActivityLibrary return row; } - #region Lookup Action Dropdown + protected void SetDropdownSelectedValue(string dropDownListID, string value) + { + DropDownList ddl = (DropDownList)this.FindControl(dropDownListID); + if (ddl != null) + { + if (!string.IsNullOrEmpty(value)) + ddl.SelectedValue = value; + } + else + Debugging.Log("Cannot find control with ID '" + dropDownListID + "'"); + } + protected TableRow AddAddRemoveDropDownList(string labelText, string controlID, int width, string defaultValue) + { + TableRow row = new TableRow(); + TableCell labelCell = new TableCell(); + TableCell controlCell = new TableCell(); + + Label oLabel = new Label(); + oLabel.Text = labelText; + oLabel.CssClass = base.LabelCssClass; + labelCell.Controls.Add(oLabel); + + DropDownList ddl = new DropDownList(); + ddl.ID = controlID; + ddl.Width = width; + + ddl.Items.Add(new ListItem("Add", "Add")); + ddl.Items.Add(new ListItem("Remove", "Remove")); + ddl.SelectedValue = defaultValue; + controlCell.Controls.Add(ddl); + + row.Cells.Add(labelCell); + row.Cells.Add(controlCell); + + return row; + } + protected void SetAddRemoveDropDownList(string dropDownListID, string value) + { + SetDropdownSelectedValue(dropDownListID, value); + } + protected string GetAddRemoveDropDownList(string dropDownListID) + { + string g = ""; + DropDownList ddl = (DropDownList)this.FindControl(dropDownListID); + if (ddl != null) + { + if (!string.IsNullOrEmpty(ddl.SelectedValue)) + g = ddl.SelectedValue.ToString(); + } + else + Debugging.Log("Cannot find control with ID '" + dropDownListID + "'"); + return g; + } protected TableRow AddLookupActionDropDownList(String labelText, String controlID, int width, String defaultValue) { TableRow row = new TableRow(); @@ -91,20 +138,9 @@ namespace Granfeldt.FIM.ActivityLibrary protected void SetLookupActionDropDownList(string dropDownListID, string value) { - DropDownList ddl = (DropDownList)this.FindControl(dropDownListID); - if (ddl != null) - { - if (!string.IsNullOrEmpty(value)) - ddl.SelectedValue = value; - } - else - Debugging.Log("Cannot find control with ID '" + dropDownListID + "'"); + SetDropdownSelectedValue(dropDownListID, value); } - #endregion - - #region Actor Dropdown - protected TableRow AddActorDropDownList(String labelText, String controlID, int width, String defaultValue) { TableRow row = new TableRow(); @@ -151,20 +187,11 @@ namespace Granfeldt.FIM.ActivityLibrary return g; } - protected void SetActorDropDownList(string dropDownListID, object Guid) + protected void SetActorDropDownList(string dropDownListID, object value) { - DropDownList ddl = (DropDownList)this.FindControl(dropDownListID); - if (ddl != null) - { - if (Guid != null) - ddl.SelectedValue = Guid.ToString(); - } - else - Debugging.Log("Cannot find control with ID '" + dropDownListID + "'"); + SetDropdownSelectedValue(dropDownListID, value.ToString()); } - #endregion - protected TableRow AddCheckbox(String labelText, String controlID, bool defaultValue) { TableRow row = new TableRow(); @@ -266,7 +293,6 @@ namespace Granfeldt.FIM.ActivityLibrary Debugging.Log("Cannot find control with ID '" + dropDownListID + "'"); } - #endregion /// /// Called when a user clicks the Save button in the Workflow Designer. diff --git a/Granfeldt.FIM.ActivityLibrary/Base/Base.AttributeValue/Base.AttributeValue.cs b/Granfeldt.FIM.ActivityLibrary/Base/Base.AttributeValue/Base.AttributeValue.cs index e4abb25..94a38f1 100644 --- a/Granfeldt.FIM.ActivityLibrary/Base/Base.AttributeValue/Base.AttributeValue.cs +++ b/Granfeldt.FIM.ActivityLibrary/Base/Base.AttributeValue/Base.AttributeValue.cs @@ -7,182 +7,180 @@ using Microsoft.ResourceManagement.WebServices.WSResourceManagement; namespace Granfeldt.FIM.ActivityLibrary { - public class AttributeValue - { - //Constructors - /// - /// Creates a new instance of the object type AttributeValue. - /// - public AttributeValue() - { - this.IsResolved = false; - } - /// - /// Creates a new instance of the object type AttributeValue, and sets source and target attribute name. - /// - /// Name of the source attribute. - /// Name of the target attribute. - public AttributeValue(string sourceAttributeName, string targetAttributeName) - { - this.SourceAttributeName = sourceAttributeName; - this.TargetAttributeName = targetAttributeName; - this.IsResolved = false; - } - //Fields - private object _sourceAttributeValue; + public class AttributeValue + { + //Constructors + /// + /// Creates a new instance of the object type AttributeValue. + /// + public AttributeValue() + { + this.IsResolved = false; + } + /// + /// Creates a new instance of the object type AttributeValue, and sets source and target attribute name. + /// + /// Name of the source attribute. + /// Name of the target attribute. + public AttributeValue(string sourceAttributeName, string targetAttributeName) + { + this.SourceAttributeName = sourceAttributeName; + this.TargetAttributeName = targetAttributeName; + this.IsResolved = false; + } + //Fields + private object _sourceAttributeValue; - //Properties - public string SourceAttributeName { get; set; } - public object SourceAttributeValue - { - get - { - return this._sourceAttributeValue; - } - set - { - this._sourceAttributeValue = value; - this.IsResolved = true; - } - } - public string TargetAttributeName { get; set; } - public object TargetAttributeValue { get; set; } - public bool IsDelete { get; private set; } - /// - /// Indicates if the SourceAttributeName have been resolved. - /// This is set when SourceAttributeValue is set. - /// - public bool IsResolved { get; private set; } - /// - /// Tells if the SourceAttributeValue should be resolved from SourceAttributeName. - /// It is decided by testing if the SourceAttributeName contains a resolveable string. - /// - public bool ShouldResolve - { - get - { - if (this.IsResolved) - { - return false; - } - else - { - if (this.SourceAttributeName != null) - return this.SourceAttributeName.Trim().Contains("[//"); - else - return false; - } - } - } + //Properties + public string SourceAttributeName { get; set; } + public object SourceAttributeValue + { + get + { + return this._sourceAttributeValue; + } + set + { + this._sourceAttributeValue = value; + this.IsResolved = true; + } + } + public string TargetAttributeName { get; set; } + public object TargetAttributeValue { get; set; } + public bool IsDelete { get; private set; } + /// + /// Indicates if the SourceAttributeName have been resolved. + /// This is set when SourceAttributeValue is set. + /// + public bool IsResolved { get; private set; } + /// + /// Tells if the SourceAttributeValue should be resolved from SourceAttributeName. + /// It is decided by testing if the SourceAttributeName contains a resolveable string. + /// + public bool ShouldResolve + { + get + { + if (this.IsResolved) + { + return false; + } + else + { + if (this.SourceAttributeName != null) + return this.SourceAttributeName.Trim().Contains("[//"); + else + return false; + } + } + } - #region Methods - /// - /// Returns this AttributeValue as an UpdateRequestParameter used for updating resources in FIM. - /// - /// ObjectID of the resource being updated. - /// Tells the method what type of update to return. - /// If isDelete is true a UpdateMode is set to: Remove. - /// - /// - public UpdateRequestParameter ToUpdateRequestParameter(Guid objectId,bool isDelete) - { - if (!isDelete) - return new UpdateRequestParameter(objectId, this.TargetAttributeName, UpdateMode.Modify, FIMAttributeUtilities.FormatValue(this.SourceAttributeValue), false); - else - { - return new UpdateRequestParameter(objectId, this.TargetAttributeName, UpdateMode.Remove, this.TargetAttributeValue, false); - } - } - /// - /// Returns this AttributeValue as an UpdateRequestParameter used for updating resources in FIM, without specifying which object to update. - /// - /// Tells the method what type of update to return. - /// If isDelete is true a UpdateMode is set to: Remove. - /// - public UpdateRequestParameter ToUpdateRequestParameter(bool isDelete) - { + #region Methods + /// + /// Returns this AttributeValue as an UpdateRequestParameter used for updating resources in FIM. + /// + /// ObjectID of the resource being updated. + /// Tells the method what type of update to return. + /// If isDelete is true a UpdateMode is set to: Remove. + /// + /// + public UpdateRequestParameter ToUpdateRequestParameter(Guid objectId, bool isDelete) + { + if (!isDelete) + return new UpdateRequestParameter(objectId, this.TargetAttributeName, UpdateMode.Modify, FIMAttributeUtilities.FormatValue(this.SourceAttributeValue), false); + else + { + return new UpdateRequestParameter(objectId, this.TargetAttributeName, UpdateMode.Remove, this.TargetAttributeValue, false); + } + } + /// + /// Returns this AttributeValue as an UpdateRequestParameter used for updating resources in FIM, without specifying which object to update. + /// + /// Tells the method what type of update to return. + /// If isDelete is true a UpdateMode is set to: Remove. + /// + public UpdateRequestParameter ToUpdateRequestParameter(bool isDelete) + { - if (!isDelete) - return new UpdateRequestParameter(this.TargetAttributeName, UpdateMode.Modify, FIMAttributeUtilities.FormatValue(this.SourceAttributeValue), false); - else - { - return new UpdateRequestParameter(this.TargetAttributeName, UpdateMode.Remove, this.TargetAttributeValue, false); - } - - } - /// - /// Compares the source value with the supplied readValue parameter. - /// Also sets IsDelete to true or false - /// - /// A value to compare with the SourceValue. - /// - public virtual bool ShouldUpdate(object readValue) - { - + if (!isDelete) + return new UpdateRequestParameter(this.TargetAttributeName, UpdateMode.Modify, FIMAttributeUtilities.FormatValue(this.SourceAttributeValue), false); + else + { + return new UpdateRequestParameter(this.TargetAttributeName, UpdateMode.Remove, this.TargetAttributeValue, false); + } - // we need the original (non-converted) value if we are doing a removal as we must specify the original value (even a local date/time) - // object originalTargetValue = this.TargetAttributeValue; - object target = FIMAttributeUtilities.FormatValue(readValue); - object source = FIMAttributeUtilities.FormatValue(this.SourceAttributeValue); + } + /// + /// Compares the source value with the supplied readValue parameter. + /// Also sets IsDelete to true or false + /// + /// A value to compare with the SourceValue. + /// + public virtual bool ShouldUpdate(object readValue) + { + // we need the original (non-converted) value if we are doing a removal as we must specify the original value (even a local date/time) + // object originalTargetValue = this.TargetAttributeValue; + object target = FIMAttributeUtilities.FormatValue(readValue); + object source = FIMAttributeUtilities.FormatValue(this.SourceAttributeValue); - return getShouldUpdate(target, source); - } - /// - /// Compares the Target attribute value with the existing source attribute value. If the source attribute value is not set, - /// it will be compared on as a null value. - /// - /// Result of compare - public virtual bool ShouldUpdate() - { - object target = FIMAttributeUtilities.FormatValue(this.TargetAttributeValue); - object source = FIMAttributeUtilities.FormatValue(this.SourceAttributeValue); + return getShouldUpdate(target, source); + } + /// + /// Compares the Target attribute value with the existing source attribute value. If the source attribute value is not set, + /// it will be compared on as a null value. + /// + /// Result of compare + public virtual bool ShouldUpdate() + { + object target = FIMAttributeUtilities.FormatValue(this.TargetAttributeValue); + object source = FIMAttributeUtilities.FormatValue(this.SourceAttributeValue); - Debugging.Log(String.Format("Comparing source: {0} and target: {1}, containing the values: {2} / {3}", this.SourceAttributeName, this.TargetAttributeName, this.SourceAttributeValue, this.TargetAttributeValue)); - bool result = getShouldUpdate(target, source); - Debugging.Log(String.Format("Comparison resulted in: {0}",result)); - return result; - } - /// - /// Private method for comparing Source and Target attributes - /// - /// Taget value - /// Source value - /// Whether or not the target attribute should be updated. - private bool getShouldUpdate(object target, object source) - { - if (FIMAttributeUtilities.ValuesAreDifferent(source, target)) - { - if (source == null) - { - // we are in a delete state - Debugging.Log(string.Format("Deleting value '{1}' from {0}", this.TargetAttributeName, target == null ? "(null)" : target)); - this.IsDelete = true; - } - else - { - // we are in an update state - Debugging.Log(string.Format("Updating {0} from '{1}' to '{2}'", this.TargetAttributeName, target == null ? "(null)" : target, source)); - this.IsDelete = false; - } - return true; - } - else - { - Debugging.Log(string.Format("No need to update {0}. Value is already {1}", this.TargetAttributeName, this.TargetAttributeValue == null ? "(null)" : this.TargetAttributeValue)); - this.IsDelete = false; - return false; - } - } - /// - /// Sets the TargetAttributeValue on this AttributeValue based on the it's current TargetAttributeName. - /// - /// the ResourceType object to pull the attribute value from. - internal virtual void SetValues(ResourceType resource) - { - TargetAttributeValue = resource[this.TargetAttributeName] != null ? resource[this.TargetAttributeName] : null; - Debugging.Log(this.TargetAttributeName, this.TargetAttributeValue); - } - #endregion - } + Debugging.Log(String.Format("Comparing source: {0} and target: {1}, containing the values: {2} / {3}", this.SourceAttributeName, this.TargetAttributeName, this.SourceAttributeValue, this.TargetAttributeValue)); + bool result = getShouldUpdate(target, source); + Debugging.Log(String.Format("Comparison resulted in: {0}", result)); + return result; + } + /// + /// Private method for comparing Source and Target attributes + /// + /// Taget value + /// Source value + /// Whether or not the target attribute should be updated. + private bool getShouldUpdate(object target, object source) + { + if (FIMAttributeUtilities.ValuesAreDifferent(source, target)) + { + if (source == null) + { + // we are in a delete state + Debugging.Log(string.Format("Deleting value '{1}' from {0}", this.TargetAttributeName, target == null ? "(null)" : target)); + this.IsDelete = true; + } + else + { + // we are in an update state + Debugging.Log(string.Format("Updating {0} from '{1}' to '{2}'", this.TargetAttributeName, target == null ? "(null)" : target, source)); + this.IsDelete = false; + } + return true; + } + else + { + Debugging.Log(string.Format("No need to update {0}. Value is already {1}", this.TargetAttributeName, this.TargetAttributeValue == null ? "(null)" : this.TargetAttributeValue)); + this.IsDelete = false; + return false; + } + } + /// + /// Sets the TargetAttributeValue on this AttributeValue based on the it's current TargetAttributeName. + /// + /// the ResourceType object to pull the attribute value from. + internal virtual void SetValues(ResourceType resource) + { + TargetAttributeValue = resource[this.TargetAttributeName] != null ? resource[this.TargetAttributeName] : null; + Debugging.Log(this.TargetAttributeName, this.TargetAttributeValue); + } + #endregion + } } diff --git a/Granfeldt.FIM.ActivityLibrary/Base/Base.Common/Base.Common.cs b/Granfeldt.FIM.ActivityLibrary/Base/Base.Common/Base.Common.cs index c14e487..ad59b64 100644 --- a/Granfeldt.FIM.ActivityLibrary/Base/Base.Common/Base.Common.cs +++ b/Granfeldt.FIM.ActivityLibrary/Base/Base.Common/Base.Common.cs @@ -10,7 +10,6 @@ using Microsoft.Win32; namespace Granfeldt.FIM.ActivityLibrary { - public class WellKnownGuids { public static Guid BuiltInSynchronizationAccount = new Guid("fb89aefa-5ea1-47f1-8890-abe7797d6497"); diff --git a/Granfeldt.FIM.ActivityLibrary/Base/Helper.AddRemoveMultiValueAsNeededActivity.Designer.cs b/Granfeldt.FIM.ActivityLibrary/Base/Helper.AddRemoveMultiValueAsNeededActivity.Designer.cs new file mode 100644 index 0000000..c1c9cf2 --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Base/Helper.AddRemoveMultiValueAsNeededActivity.Designer.cs @@ -0,0 +1,119 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Collections; +using System.Reflection; +using System.Workflow.ComponentModel; +using System.Workflow.ComponentModel.Design; +using System.Workflow.ComponentModel.Compiler; +using System.Workflow.ComponentModel.Serialization; +using System.Workflow.Runtime; +using System.Workflow.Activities; +using System.Workflow.Activities.Rules; + +namespace Granfeldt.FIM.ActivityLibrary +{ + public partial class AddRemoveMultiValueActivityAsNeeded + { + #region Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + [System.Diagnostics.DebuggerNonUserCode] + [System.CodeDom.Compiler.GeneratedCode("", "")] + private void InitializeComponent() + { + this.CanModifyActivities = true; + System.Workflow.Activities.CodeCondition codecondition1 = new System.Workflow.Activities.CodeCondition(); + System.Workflow.ComponentModel.ActivityBind activitybind1 = new System.Workflow.ComponentModel.ActivityBind(); + this.UpdateTarget = new Microsoft.ResourceManagement.Workflow.Activities.UpdateResourceActivity(); + this.NothingToDo = new System.Workflow.Activities.IfElseBranchActivity(); + this.DoUpdate = new System.Workflow.Activities.IfElseBranchActivity(); + this.ShouldUpdate = new System.Workflow.Activities.IfElseActivity(); + this.ReadTarget = new Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity(); + this.PrepareReadResource = new System.Workflow.Activities.CodeActivity(); + // + // UpdateTarget + // + this.UpdateTarget.ActorId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.UpdateTarget.ApplyAuthorizationPolicy = false; + this.UpdateTarget.Name = "UpdateTarget"; + this.UpdateTarget.ResourceId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.UpdateTarget.UpdateParameters = null; + // + // NothingToDo + // + this.NothingToDo.Name = "NothingToDo"; + // + // DoUpdate + // + this.DoUpdate.Activities.Add(this.UpdateTarget); + codecondition1.Condition += new System.EventHandler(this.ShouldUpdate_Condition); + this.DoUpdate.Condition = codecondition1; + this.DoUpdate.Name = "DoUpdate"; + // + // ShouldUpdate + // + this.ShouldUpdate.Activities.Add(this.DoUpdate); + this.ShouldUpdate.Activities.Add(this.NothingToDo); + this.ShouldUpdate.Name = "ShouldUpdate"; + // + // ReadTarget + // + this.ReadTarget.ActorId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.ReadTarget.Name = "ReadTarget"; + activitybind1.Name = "AddRemoveMultiValueActivityAsNeeded"; + activitybind1.Path = "TargetResource"; + this.ReadTarget.ResourceId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.ReadTarget.SelectionAttributes = null; + this.ReadTarget.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity.ResourceProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind1))); + // + // PrepareReadResource + // + this.PrepareReadResource.Name = "PrepareReadResource"; + this.PrepareReadResource.ExecuteCode += new System.EventHandler(this.PrepareReadResource_ExecuteCode); + // + // AddRemoveMultiValueActivityAsNeeded + // + this.Activities.Add(this.PrepareReadResource); + this.Activities.Add(this.ReadTarget); + this.Activities.Add(this.ShouldUpdate); + this.Name = "AddRemoveMultiValueActivityAsNeeded"; + this.CanModifyActivities = false; + + } + + #endregion + + private CodeActivity PrepareReadResource; + + private Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity ReadTarget; + + private IfElseBranchActivity NothingToDo; + + private IfElseBranchActivity DoUpdate; + + private IfElseActivity ShouldUpdate; + + private Microsoft.ResourceManagement.Workflow.Activities.UpdateResourceActivity UpdateTarget; + + + + + + + + + + + + + + + + + + } +} diff --git a/Granfeldt.FIM.ActivityLibrary/Base/Helper.AddRemoveMultiValueAsNeededActivity.cs b/Granfeldt.FIM.ActivityLibrary/Base/Helper.AddRemoveMultiValueAsNeededActivity.cs new file mode 100644 index 0000000..09dbd4e --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Base/Helper.AddRemoveMultiValueAsNeededActivity.cs @@ -0,0 +1,221 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Workflow.ComponentModel; +using System.Workflow.ComponentModel.Design; +using System.Workflow.ComponentModel.Compiler; +using System.Workflow.ComponentModel.Serialization; +using System.Workflow.Runtime; +using System.Workflow.Activities; +using System.Workflow.Activities.Rules; +using Microsoft.ResourceManagement.Workflow.Activities; +using System.Collections.ObjectModel; +using Microsoft.ResourceManagement.WebServices; +using Microsoft.ResourceManagement.WebServices.WSResourceManagement; + +namespace Granfeldt.FIM.ActivityLibrary +{ + public partial class AddRemoveMultiValueActivityAsNeeded : SequenceActivity + { + public static DependencyProperty ActionProperty = DependencyProperty.Register("Action", typeof(System.String), typeof(AddRemoveMultiValueActivityAsNeeded)); + public static DependencyProperty TargetResourceProperty = DependencyProperty.Register("TargetResource", typeof(Microsoft.ResourceManagement.WebServices.WSResourceManagement.ResourceType), typeof(AddRemoveMultiValueActivityAsNeeded)); + public static DependencyProperty DestinationProperty = DependencyProperty.Register("Destination", typeof(string), typeof(AddRemoveMultiValueActivityAsNeeded)); + + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] + [BrowsableAttribute(true)] + [CategoryAttribute("Misc")] + public String Action + { + get + { + return ((string)(base.GetValue(ActionProperty))); + } + set + { + base.SetValue(ActionProperty, value); + } + } + + public static DependencyProperty TargetIdToUpdateProperty = DependencyProperty.Register("TargetIdToUpdate", typeof(Guid), typeof(AddRemoveMultiValueActivityAsNeeded)); + [Description("TargetIdToUpdate")] + [Category("TargetIdToUpdate Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Guid TargetIdToUpdate + { + get + { + return ((Guid)(base.GetValue(AddRemoveMultiValueActivityAsNeeded.TargetIdToUpdateProperty))); + } + set + { + base.SetValue(AddRemoveMultiValueActivityAsNeeded.TargetIdToUpdateProperty, value); + } + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + [Category("Properties")] + public string Destination + { + get + { + return (string)base.GetValue(DestinationProperty); + } + set + { + base.SetValue(DestinationProperty, value); + } + } + + public static DependencyProperty ValueToAddOrRemoveProperty = DependencyProperty.Register("ValueToAddOrRemove", typeof(object), typeof(AddRemoveMultiValueActivityAsNeeded)); + [Description("ValueToAddOrRemove")] + [Category("ValueToAddOrRemove Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public object ValueToAddOrRemove + { + get + { + return ((object)(base.GetValue(AddRemoveMultiValueActivityAsNeeded.ValueToAddOrRemoveProperty))); + } + set + { + base.SetValue(AddRemoveMultiValueActivityAsNeeded.ValueToAddOrRemoveProperty, value); + } + } + + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] + [BrowsableAttribute(true)] + [CategoryAttribute("Parameters")] + public Microsoft.ResourceManagement.WebServices.WSResourceManagement.ResourceType TargetResource + { + get + { + return ((Microsoft.ResourceManagement.WebServices.WSResourceManagement.ResourceType)(base.GetValue(TargetResourceProperty))); + } + set + { + base.SetValue(TargetResourceProperty, value); + } + } + + SequentialWorkflow containingWorkflow; + List NewValues = new List(); + + public AddRemoveMultiValueActivityAsNeeded() + { + InitializeComponent(); + } + + private void PrepareReadResource_ExecuteCode(object sender, EventArgs e) + { + Debugging.Log("Enter AddRemoveMultiValue-PrepareReadResource_ExecuteCode"); + try + { + if (!SequentialWorkflow.TryGetContainingWorkflow(this, out containingWorkflow)) + { + throw new InvalidOperationException("Could not get parent workflow!"); + } + ReadTarget.ActorId = WellKnownGuids.FIMServiceAccount; + ReadTarget.ResourceId = this.TargetIdToUpdate; + ReadTarget.SelectionAttributes = new string[] { this.Destination }; + } + catch (Exception ex) + { + Debugging.Log(string.Format("Error: '{0}'", ex.Message)); + } + Debugging.Log("Exit AddRemoveMultiValue-PrepareReadResource_ExecuteCode"); + } + + private void ShouldUpdate_Condition(object sender, ConditionalEventArgs e) + { + Debugging.Log("Enter :: AddRemoveMultiValue-ShouldUpdate_Condition"); + NewValues.Add(this.ValueToAddOrRemove); + Debugging.Log("New value", this.NewValues == null ? "(null)" : this.NewValues.FirstOrDefault().ToString()); + + Debugging.Log(string.Format("Action: {0}", Action)); + try + { + // convert list of unique identifiers to list of guids + Debugging.Log("Begin converting to list"); + List currentvalues = new List(); + if (this.ReadTarget.Resource[this.Destination] != null) + { + Debugging.Log("Type", this.ReadTarget.Resource[this.Destination].GetType()); + foreach (UniqueIdentifier u in (List)this.ReadTarget.Resource[this.Destination]) + { + Debugging.Log(string.Format("Guid: {0}", u.ToString())); + currentvalues.Add(u.GetGuid()); + } + } + Debugging.Log("End converting to list"); + + e.Result = false; + if (this.Action.Equals("add", StringComparison.InvariantCultureIgnoreCase)) + { + if (currentvalues == null) + { + Debugging.Log("There is an add and no current values"); + e.Result = true; + } + else + { + if (NewValues.Except(currentvalues).Count() > 0) + { + Debugging.Log("There is an add"); + e.Result = true; + } + else + { + Debugging.Log("There is a add but its already included"); + e.Result = false; + } + } + } + else + { + if (currentvalues == null) + { + Debugging.Log("There is a remove but target value is already empty"); + e.Result = false; + } + else + { + if (currentvalues.Intersect(NewValues).Count() > 0) + { + Debugging.Log("There is a remove"); + e.Result = true; + } + else + { + Debugging.Log("There is a remove but target value is currently included"); + e.Result = false; + } + } + } + if (e.Result) + { + // prepare update request + UpdateTarget.ActorId = WellKnownGuids.FIMServiceAccount; + UpdateTarget.ResourceId = this.TargetIdToUpdate; + UpdateRequestParameter[] UpdateParameters = new UpdateRequestParameter[] { + new Microsoft.ResourceManagement.WebServices.WSResourceManagement.UpdateRequestParameter( + this.Destination, + this.Action.Equals("add", StringComparison.OrdinalIgnoreCase) ? UpdateMode.Insert : UpdateMode.Remove, + NewValues.First())}; + UpdateTarget.UpdateParameters = UpdateParameters; + } + } + catch (Exception ex) + { + Debugging.Log(string.Format("AddRemoveMultiValue-ShouldUpdate_Condition, error: '{0}'", ex.Message)); + } + Debugging.Log("Exit AddRemoveMultiValue-ShouldUpdate_Condition"); + } + + } +} diff --git a/Granfeldt.FIM.ActivityLibrary/Customer.ReconcileSoftwareGroupMembers/Customer.ReconcileSoftwareGroupMembers.Designer.cs b/Granfeldt.FIM.ActivityLibrary/Customer.ReconcileSoftwareGroupMembers/Customer.ReconcileSoftwareGroupMembers.Designer.cs new file mode 100644 index 0000000..068e650 --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Customer.ReconcileSoftwareGroupMembers/Customer.ReconcileSoftwareGroupMembers.Designer.cs @@ -0,0 +1,152 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Collections; +using System.Reflection; +using System.Workflow.ComponentModel; +using System.Workflow.ComponentModel.Design; +using System.Workflow.ComponentModel.Compiler; +using System.Workflow.ComponentModel.Serialization; +using System.Workflow.Runtime; +using System.Workflow.Activities; +using System.Workflow.Activities.Rules; + +namespace Granfeldt.FIM.ActivityLibrary +{ + public partial class ReconcileSoftwareGroupMembersActivity + { + #region Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + [System.Diagnostics.DebuggerNonUserCode] + [System.CodeDom.Compiler.GeneratedCode("", "")] + private void InitializeComponent() + { + this.CanModifyActivities = true; + System.Workflow.Activities.CodeCondition codecondition1 = new System.Workflow.Activities.CodeCondition(); + System.Collections.Generic.List list_11 = new System.Collections.Generic.List(); + System.Workflow.ComponentModel.ActivityBind activitybind1 = new System.Workflow.ComponentModel.ActivityBind(); + System.Workflow.ComponentModel.ActivityBind activitybind2 = new System.Workflow.ComponentModel.ActivityBind(); + this.UpdateExplicitComputerMembers = new Microsoft.ResourceManagement.Workflow.Activities.UpdateResourceActivity(); + this.NothingToDo = new System.Workflow.Activities.IfElseBranchActivity(); + this.UpdateExplicitMember = new System.Workflow.Activities.IfElseBranchActivity(); + this.EnumerateComputers = new Granfeldt.FIM.ActivityLibrary.FindResourcesActivity(); + this.UpdateMembers = new System.Workflow.Activities.IfElseActivity(); + this.FindUsersComputers = new System.Workflow.Activities.ReplicatorActivity(); + this.ReadTarget = new Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity(); + this.PrepareReadTarget = new System.Workflow.Activities.CodeActivity(); + // + // UpdateExplicitComputerMembers + // + this.UpdateExplicitComputerMembers.ActorId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.UpdateExplicitComputerMembers.ApplyAuthorizationPolicy = false; + this.UpdateExplicitComputerMembers.Name = "UpdateExplicitComputerMembers"; + this.UpdateExplicitComputerMembers.ResourceId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.UpdateExplicitComputerMembers.UpdateParameters = null; + // + // NothingToDo + // + this.NothingToDo.Name = "NothingToDo"; + // + // UpdateExplicitMember + // + this.UpdateExplicitMember.Activities.Add(this.UpdateExplicitComputerMembers); + codecondition1.Condition += new System.EventHandler(this.UpdateTarget_Condition); + this.UpdateExplicitMember.Condition = codecondition1; + this.UpdateExplicitMember.Name = "UpdateExplicitMember"; + // + // EnumerateComputers + // + this.EnumerateComputers.ActorId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.EnumerateComputers.Attributes = null; + this.EnumerateComputers.EnumeratedResourceIDs = null; + this.EnumerateComputers.EnumeratedResources = list_11; + this.EnumerateComputers.Name = "EnumerateComputers"; + this.EnumerateComputers.PageSize = 0; + this.EnumerateComputers.SortingAttributes = null; + this.EnumerateComputers.TotalResultsCount = 0; + this.EnumerateComputers.XPathFilter = null; + // + // UpdateMembers + // + this.UpdateMembers.Activities.Add(this.UpdateExplicitMember); + this.UpdateMembers.Activities.Add(this.NothingToDo); + this.UpdateMembers.Name = "UpdateMembers"; + activitybind1.Name = "ReconcileSoftwareGroupMembersActivity"; + activitybind1.Path = "usermembers"; + // + // FindUsersComputers + // + this.FindUsersComputers.Activities.Add(this.EnumerateComputers); + this.FindUsersComputers.ExecutionType = System.Workflow.Activities.ExecutionType.Sequence; + this.FindUsersComputers.Name = "FindUsersComputers"; + this.FindUsersComputers.ChildInitialized += new System.EventHandler(this.FindUsersComputers_ChildInitialized); + this.FindUsersComputers.ChildCompleted += new System.EventHandler(this.FindUsersComputers_ChildCompleted); + this.FindUsersComputers.Completed += new System.EventHandler(this.FindUsersComputers_Completed); + this.FindUsersComputers.Initialized += new System.EventHandler(this.FindUsersComputers_Initialized); + this.FindUsersComputers.SetBinding(System.Workflow.Activities.ReplicatorActivity.InitialChildDataProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind1))); + // + // ReadTarget + // + this.ReadTarget.ActorId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.ReadTarget.Name = "ReadTarget"; + activitybind2.Name = "ReconcileSoftwareGroupMembersActivity"; + activitybind2.Path = "TargetResource"; + this.ReadTarget.ResourceId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.ReadTarget.SelectionAttributes = null; + this.ReadTarget.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity.ResourceProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind2))); + // + // PrepareReadTarget + // + this.PrepareReadTarget.Name = "PrepareReadTarget"; + this.PrepareReadTarget.ExecuteCode += new System.EventHandler(this.PrepareReadTarget_ExecuteCode); + // + // ReconcileSoftwareGroupMembersActivity + // + this.Activities.Add(this.PrepareReadTarget); + this.Activities.Add(this.ReadTarget); + this.Activities.Add(this.FindUsersComputers); + this.Activities.Add(this.UpdateMembers); + this.Name = "ReconcileSoftwareGroupMembersActivity"; + this.CanModifyActivities = false; + + } + + #endregion + + private Microsoft.ResourceManagement.Workflow.Activities.UpdateResourceActivity UpdateExplicitComputerMembers; + + private IfElseBranchActivity NothingToDo; + + private IfElseBranchActivity UpdateExplicitMember; + + private IfElseActivity UpdateMembers; + + private FindResourcesActivity EnumerateComputers; + + private ReplicatorActivity FindUsersComputers; + + private Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity ReadTarget; + + private CodeActivity PrepareReadTarget; + + + + + + + + + + + + + + + + + } +} diff --git a/Granfeldt.FIM.ActivityLibrary/Customer.ReconcileSoftwareGroupMembers/Customer.ReconcileSoftwareGroupMembers.SettingsPart.cs b/Granfeldt.FIM.ActivityLibrary/Customer.ReconcileSoftwareGroupMembers/Customer.ReconcileSoftwareGroupMembers.SettingsPart.cs new file mode 100644 index 0000000..bd93d32 --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Customer.ReconcileSoftwareGroupMembers/Customer.ReconcileSoftwareGroupMembers.SettingsPart.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Web.UI.WebControls; +using System.Workflow.ComponentModel; +using Microsoft.IdentityManagement.WebUI.Controls; +using Microsoft.ResourceManagement.Workflow.Activities; + +namespace Granfeldt.FIM.ActivityLibrary.WebUIs +{ + class ReconcileSoftwareGroupMembersActivitySettingsPart : BaseActivitySettingsPart + { + + const string UserMembersAttributeName = "UserMembersAttributeName"; + const string ComputerMembersAttributeName = "ComputerMembersAttributeName"; + + protected override void CreateChildControls() + { + Table layoutTable; + layoutTable = new Table(); + + // width is set to 100% of the control size + layoutTable.Width = Unit.Percentage(100.0); + layoutTable.BorderWidth = 0; + layoutTable.CellPadding = 2; + + // add a TableRow for each textbox in the UI + layoutTable.Rows.Add(this.AddTableRowTextBox("User members attributename:", "txt" + UserMembersAttributeName, 400, 100, false, "ExplicitMemberComputerOwners")); + layoutTable.Rows.Add(this.AddTableRowTextBox("Computer members attributename:", "txt" + ComputerMembersAttributeName, 400, 100, false, "ExplicitMember")); + this.Controls.Add(layoutTable); + base.CreateChildControls(); + } + + public override Activity GenerateActivityOnWorkflow(SequentialWorkflow workflow) + { + if (!this.ValidateInputs()) + { + return null; + } + ReconcileSoftwareGroupMembersActivity act = new ReconcileSoftwareGroupMembersActivity(); + act.ComputerMembersAttributeName = this.GetText("txt" + ComputerMembersAttributeName); + act.UserMembersAttributeName = this.GetText("txt" + UserMembersAttributeName); + return act; + } + + public override void LoadActivitySettings(Activity activity) + { + ReconcileSoftwareGroupMembersActivity thisActivity = activity as ReconcileSoftwareGroupMembersActivity; + if (thisActivity != null) + { + this.SetText("txt" + UserMembersAttributeName, thisActivity.UserMembersAttributeName); + this.SetText("txt" + ComputerMembersAttributeName, thisActivity.ComputerMembersAttributeName); + } + } + + public override ActivitySettingsPartData PersistSettings() + { + ActivitySettingsPartData data = new ActivitySettingsPartData(); + data[UserMembersAttributeName] = this.GetText("txt" + UserMembersAttributeName); + data[ComputerMembersAttributeName] = this.GetText("txt" + ComputerMembersAttributeName); + return data; + } + + public override void RestoreSettings(ActivitySettingsPartData data) + { + if (null != data) + { + this.SetText("txt" + UserMembersAttributeName, (string)data[UserMembersAttributeName]); + this.SetText("txt" + ComputerMembersAttributeName, (string)data[ComputerMembersAttributeName]); + } + } + + public override void SwitchMode(ActivitySettingsPartMode mode) + { + bool isDisabled = (mode != ActivitySettingsPartMode.Edit); + this.SetTextBoxReadOnlyOption("txt" + UserMembersAttributeName, isDisabled); + this.SetTextBoxReadOnlyOption("txt" + ComputerMembersAttributeName, isDisabled); + } + + public override string Title + { + get { return "Reconcile software group members"; } + } + + public override bool ValidateInputs() + { + return true; + } + } +} diff --git a/Granfeldt.FIM.ActivityLibrary/Customer.ReconcileSoftwareGroupMembers/Customer.ReconcileSoftwareGroupMembers.cs b/Granfeldt.FIM.ActivityLibrary/Customer.ReconcileSoftwareGroupMembers/Customer.ReconcileSoftwareGroupMembers.cs new file mode 100644 index 0000000..f4b111a --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Customer.ReconcileSoftwareGroupMembers/Customer.ReconcileSoftwareGroupMembers.cs @@ -0,0 +1,219 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Collections; +using System.Linq; +using System.Workflow.ComponentModel; +using System.Workflow.ComponentModel.Design; +using System.Workflow.ComponentModel.Compiler; +using System.Workflow.ComponentModel.Serialization; +using System.Workflow.Runtime; +using System.Workflow.Activities; +using System.Workflow.Activities.Rules; +using Microsoft.ResourceManagement.Workflow.Activities; +using System.Collections.Generic; +using Microsoft.ResourceManagement.WebServices; +using Microsoft.ResourceManagement.WebServices.WSResourceManagement; + +namespace Granfeldt.FIM.ActivityLibrary +{ + public partial class ReconcileSoftwareGroupMembersActivity : SequenceActivity + { + + #region Properties + + // ExplicitMemberComputerOwners + public static DependencyProperty UserMembersAttributeNameProperty = DependencyProperty.Register("UserMembersAttributeName", typeof(string), typeof(ReconcileSoftwareGroupMembersActivity)); + [Description("UserMembersAttributeName")] + [Category("UserMembersAttributeName Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public string UserMembersAttributeName + { + get + { + return ((string)(base.GetValue(ReconcileSoftwareGroupMembersActivity.UserMembersAttributeNameProperty))); + } + set + { + base.SetValue(ReconcileSoftwareGroupMembersActivity.UserMembersAttributeNameProperty, value); + } + } + + // ExplicitMember + public static DependencyProperty ComputerMembersAttributeNameProperty = DependencyProperty.Register("ComputerMembersAttributeName", typeof(string), typeof(ReconcileSoftwareGroupMembersActivity)); + [Description("ComputerMembersAttributeName")] + [Category("ComputerMembersAttributeName Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public string ComputerMembersAttributeName + { + get + { + return ((string)(base.GetValue(ReconcileSoftwareGroupMembersActivity.ComputerMembersAttributeNameProperty))); + } + set + { + base.SetValue(ReconcileSoftwareGroupMembersActivity.ComputerMembersAttributeNameProperty, value); + } + } + + public static DependencyProperty TargetResourceProperty = DependencyProperty.Register("TargetResource", typeof(Microsoft.ResourceManagement.WebServices.WSResourceManagement.ResourceType), typeof(Granfeldt.FIM.ActivityLibrary.ReconcileSoftwareGroupMembersActivity)); + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] + [BrowsableAttribute(true)] + [CategoryAttribute("Parameters")] + public Microsoft.ResourceManagement.WebServices.WSResourceManagement.ResourceType TargetResource + { + get + { + return ((Microsoft.ResourceManagement.WebServices.WSResourceManagement.ResourceType)(base.GetValue(Granfeldt.FIM.ActivityLibrary.ReconcileSoftwareGroupMembersActivity.TargetResourceProperty))); + } + set + { + base.SetValue(Granfeldt.FIM.ActivityLibrary.ReconcileSoftwareGroupMembersActivity.TargetResourceProperty, value); + } + } + + #endregion + + SequentialWorkflow containingWorkflow = null; + public List usermembers = new List(); + public List currentcomputermembers = new List(); + public List expectedcomputermembers = new List(); + + public ReconcileSoftwareGroupMembersActivity() + { + InitializeComponent(); + } + + void ReadTarget_Closed(object sender, ActivityExecutionStatusChangedEventArgs e) + { + Debugging.Log(string.Format("Activity {0} result", e.Activity.Name), e.ExecutionResult); + try + { + // pick up the value of the multivalue attributes read from the target + if (this.ReadTarget.Resource[this.UserMembersAttributeName] != null) + { + foreach (UniqueIdentifier u in this.ReadTarget.Resource[this.UserMembersAttributeName] as List) + { + Debugging.Log("current user member objectid", u); + usermembers.Add(u.GetGuid()); + } + } + else + { + Debugging.Log("no current user members"); + } + + if (this.ReadTarget.Resource[this.ComputerMembersAttributeName] != null) + { + foreach (UniqueIdentifier u in this.ReadTarget.Resource[this.ComputerMembersAttributeName] as List) + { + Debugging.Log("current computer member objectid", u); + currentcomputermembers.Add(u.GetGuid()); + } + } + else + { + Debugging.Log("no current computer members"); + } + } + catch (Exception ex) + { + Debugging.Log(ex); + } + } + + void EnumerateComputersClosed(object sender, ActivityExecutionStatusChangedEventArgs e) + { + Debugging.Log(string.Format("{0} {1} with result: {2}", e.ExecutionStatus, e.Activity.Name, e.ExecutionResult)); + } + + private void PrepareReadTarget_ExecuteCode(object sender, EventArgs e) + { + if (!SequentialWorkflow.TryGetContainingWorkflow(this, out containingWorkflow)) + { + throw new InvalidOperationException("Could not get parent workflow!"); + } + ReadTarget.ActorId = WellKnownGuids.FIMServiceAccount; + ReadTarget.ResourceId = containingWorkflow.TargetId; + ReadTarget.SelectionAttributes = new string[] { this.UserMembersAttributeName, this.ComputerMembersAttributeName }; + ReadTarget.Closed += new System.EventHandler(ReadTarget_Closed); + } + + private void FindUsersComputers_ChildInitialized(object sender, ReplicatorChildEventArgs e) + { + Debugging.Log("child initialized"); + Debugging.Log("activity", e.Activity.Name); + Debugging.Log("instancedata", e.InstanceData); + + // get the correct instance of the child activity + FindResourcesActivity fc = e.Activity as FindResourcesActivity; + + fc.ActorId = WellKnownGuids.FIMServiceAccount; + fc.XPathFilter = string.Format("/Computer[ComputerLocalAdministrator='{0}']", e.InstanceData as Guid?); + Debugging.Log("enumeration filter", fc.XPathFilter); + fc.Attributes = new string[] { "ObjectID" }; + fc.PageSize = 100; + fc.StatusChanged += new System.EventHandler(EnumerateComputersClosed); + fc.Faulting += new System.EventHandler(EnumerateComputersClosed); + } + + private void FindUsersComputers_ChildCompleted(object sender, ReplicatorChildEventArgs e) + { + Debugging.Log("child completed"); + // get the correct instance of the child activity + FindResourcesActivity fc = e.Activity as FindResourcesActivity; + if (fc != null) + { + Debugging.Log("enumerate computers result count", fc.TotalResultsCount); + if (fc.EnumeratedResourceIDs != null) + { + foreach (Guid computer in fc.EnumeratedResourceIDs.ToList()) + { + Debugging.Log("expected member", computer); + expectedcomputermembers.Add(computer); + } + } + } + } + + private void FindUsersComputers_Completed(object sender, EventArgs e) + { + Debugging.Log("completed"); + } + + private void FindUsersComputers_Initialized(object sender, EventArgs e) + { + Debugging.Log("initialized"); + } + + private void UpdateTarget_Condition(object sender, ConditionalEventArgs e) + { + List updateparameters = new List(); + + e.Result = false; + foreach (Guid member in currentcomputermembers.Except(expectedcomputermembers)) + { + Debugging.Log("remove currentmember", member); + e.Result = true; + updateparameters.Add( + new UpdateRequestParameter(this.ComputerMembersAttributeName, UpdateMode.Remove, member) + ); + } + foreach (Guid member in expectedcomputermembers.Except(currentcomputermembers)) + { + Debugging.Log("add expected member", member); + e.Result = true; + updateparameters.Add( + new UpdateRequestParameter(this.ComputerMembersAttributeName, UpdateMode.Insert, member) + ); + } + UpdateExplicitComputerMembers.ActorId = WellKnownGuids.FIMServiceAccount; + UpdateExplicitComputerMembers.ResourceId = containingWorkflow.TargetId; + UpdateExplicitComputerMembers.UpdateParameters = updateparameters.ToArray(); + UpdateExplicitComputerMembers.StatusChanged += new System.EventHandler(EnumerateComputersClosed); + } + + } +} diff --git a/Granfeldt.FIM.ActivityLibrary/Customer.UpdateReferenceOnRegExMatch/UpdateReferenceOnRegExMatchActivity.Designer.cs b/Granfeldt.FIM.ActivityLibrary/Customer.UpdateReferenceOnRegExMatch/UpdateReferenceOnRegExMatchActivity.Designer.cs new file mode 100644 index 0000000..758b5a7 --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Customer.UpdateReferenceOnRegExMatch/UpdateReferenceOnRegExMatchActivity.Designer.cs @@ -0,0 +1,164 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Collections; +using System.Reflection; +using System.Workflow.ComponentModel; +using System.Workflow.ComponentModel.Design; +using System.Workflow.ComponentModel.Compiler; +using System.Workflow.ComponentModel.Serialization; +using System.Workflow.Runtime; +using System.Workflow.Activities; +using System.Workflow.Activities.Rules; + +namespace Granfeldt.FIM.ActivityLibrary +{ + public partial class UpdateReferenceOnRegExMatchActivity + { + #region Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + [System.Diagnostics.DebuggerNonUserCode] + [System.CodeDom.Compiler.GeneratedCode("", "")] + private void InitializeComponent() + { + this.CanModifyActivities = true; + System.Collections.Generic.List list_11 = new System.Collections.Generic.List(); + System.Workflow.Activities.CodeCondition codecondition1 = new System.Workflow.Activities.CodeCondition(); + System.Workflow.ComponentModel.ActivityBind activitybind1 = new System.Workflow.ComponentModel.ActivityBind(); + System.Workflow.ComponentModel.ActivityBind activitybind2 = new System.Workflow.ComponentModel.ActivityBind(); + this.PrepareClearingReference = new System.Workflow.Activities.CodeActivity(); + this.PrepareUpdateReference = new System.Workflow.Activities.CodeActivity(); + this.FindUser = new Granfeldt.FIM.ActivityLibrary.FindResourcesActivity(); + this.NoClearReference = new System.Workflow.Activities.IfElseBranchActivity(); + this.YesUpdateReference = new System.Workflow.Activities.IfElseBranchActivity(); + this.UpdateUserReference = new Granfeldt.FIM.ActivityLibrary.UpdateSingleValueAttributeAsNeededActivity(); + this.DoesComputerNameContainUsername = new System.Workflow.Activities.IfElseActivity(); + this.ReadTarget = new Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity(); + this.PrepareReadTarget = new System.Workflow.Activities.CodeActivity(); + this.GetCurrentRequest = new Microsoft.ResourceManagement.Workflow.Activities.CurrentRequestActivity(); + // + // PrepareClearingReference + // + this.PrepareClearingReference.Name = "PrepareClearingReference"; + this.PrepareClearingReference.ExecuteCode += new System.EventHandler(this.PrepareClearingReferenceCode); + // + // PrepareUpdateReference + // + this.PrepareUpdateReference.Name = "PrepareUpdateReference"; + this.PrepareUpdateReference.ExecuteCode += new System.EventHandler(this.PrepareUpdateReferenceCode); + // + // FindUser + // + this.FindUser.ActorId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.FindUser.Attributes = null; + this.FindUser.EnumeratedResourceIDs = null; + this.FindUser.EnumeratedResources = list_11; + this.FindUser.Name = "FindUser"; + this.FindUser.PageSize = 0; + this.FindUser.SortingAttributes = null; + this.FindUser.TotalResultsCount = 0; + this.FindUser.XPathFilter = null; + // + // NoClearReference + // + this.NoClearReference.Activities.Add(this.PrepareClearingReference); + this.NoClearReference.Name = "NoClearReference"; + // + // YesUpdateReference + // + this.YesUpdateReference.Activities.Add(this.FindUser); + this.YesUpdateReference.Activities.Add(this.PrepareUpdateReference); + codecondition1.Condition += new System.EventHandler(this.IfComputerNameContainsUsername); + this.YesUpdateReference.Condition = codecondition1; + this.YesUpdateReference.Name = "YesUpdateReference"; + // + // UpdateUserReference + // + this.UpdateUserReference.ActorId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.UpdateUserReference.AttributeName = null; + this.UpdateUserReference.Name = "UpdateUserReference"; + this.UpdateUserReference.NewValue = null; + this.UpdateUserReference.TargetId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.UpdateUserReference.TargetResource = null; + // + // DoesComputerNameContainUsername + // + this.DoesComputerNameContainUsername.Activities.Add(this.YesUpdateReference); + this.DoesComputerNameContainUsername.Activities.Add(this.NoClearReference); + this.DoesComputerNameContainUsername.Name = "DoesComputerNameContainUsername"; + // + // ReadTarget + // + this.ReadTarget.ActorId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.ReadTarget.Name = "ReadTarget"; + activitybind1.Name = "UpdateReferenceOnRegExMatchActivity"; + activitybind1.Path = "TargetResource"; + this.ReadTarget.ResourceId = new System.Guid("00000000-0000-0000-0000-000000000000"); + this.ReadTarget.SelectionAttributes = null; + this.ReadTarget.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity.ResourceProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind1))); + // + // PrepareReadTarget + // + this.PrepareReadTarget.Name = "PrepareReadTarget"; + this.PrepareReadTarget.ExecuteCode += new System.EventHandler(this.PrepareReadTargetCode); + // + // GetCurrentRequest + // + activitybind2.Name = "UpdateReferenceOnRegExMatchActivity"; + activitybind2.Path = "CurrentRequest"; + this.GetCurrentRequest.Name = "GetCurrentRequest"; + this.GetCurrentRequest.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.CurrentRequestActivity.CurrentRequestProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind2))); + // + // UpdateReferenceOnRegExMatchActivity + // + this.Activities.Add(this.GetCurrentRequest); + this.Activities.Add(this.PrepareReadTarget); + this.Activities.Add(this.ReadTarget); + this.Activities.Add(this.DoesComputerNameContainUsername); + this.Activities.Add(this.UpdateUserReference); + this.Name = "UpdateReferenceOnRegExMatchActivity"; + this.CanModifyActivities = false; + + } + + #endregion + + private CodeActivity PrepareUpdateReference; + + private CodeActivity PrepareClearingReference; + + private UpdateSingleValueAttributeAsNeededActivity UpdateUserReference; + + private FindResourcesActivity FindUser; + + private IfElseBranchActivity NoClearReference; + + private IfElseBranchActivity YesUpdateReference; + + private IfElseActivity DoesComputerNameContainUsername; + + private CodeActivity PrepareReadTarget; + + private Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity ReadTarget; + + private Microsoft.ResourceManagement.Workflow.Activities.CurrentRequestActivity GetCurrentRequest; + + + + + + + + + + + + + + + } +} diff --git a/Granfeldt.FIM.ActivityLibrary/Customer.UpdateReferenceOnRegExMatch/UpdateReferenceOnRegExMatchActivity.SettingsPart.cs b/Granfeldt.FIM.ActivityLibrary/Customer.UpdateReferenceOnRegExMatch/UpdateReferenceOnRegExMatchActivity.SettingsPart.cs new file mode 100644 index 0000000..6c7ab98 --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Customer.UpdateReferenceOnRegExMatch/UpdateReferenceOnRegExMatchActivity.SettingsPart.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Web.UI.WebControls; +using System.Workflow.ComponentModel; +using Microsoft.IdentityManagement.WebUI.Controls; +using Microsoft.ResourceManagement.Workflow.Activities; + +namespace Granfeldt.FIM.ActivityLibrary.WebUIs +{ + class UpdateReferenceOnRegExMatchActivitySettingsPart : BaseActivitySettingsPart + { + + const string RegExFilter = "RegExFilter"; + const string PositiveRegExFilter = "PositiveRegExFilter"; + const string ComputerNameAttributeName = "ComputerNameAttribute"; + const string UserNameAttributeName = "UserNameAttributeName"; + const string TargetReferenceAttributeName = "TargetReferenceAttributeName"; + const string Actor = "Actor"; + + protected override void CreateChildControls() + { + Table layoutTable; + layoutTable = new Table(); + + // width is set to 100% of the control size + layoutTable.Width = Unit.Percentage(100.0); + layoutTable.BorderWidth = 0; + layoutTable.CellPadding = 2; + + // add a TableRow for each textbox in the UI + layoutTable.Rows.Add(this.AddTableRowTextBox("Regex Filter:", "txt" + RegExFilter, 400, 100, false, "")); + layoutTable.Rows.Add(this.AddTableRowTextBox("Positive Regex Filter:
if computername match filter, username is always updated", "txt" + PositiveRegExFilter, 400, 100, false, "")); + layoutTable.Rows.Add(this.AddTableRowTextBox("ComputerName attribute:", "txt" + ComputerNameAttributeName, 400, 100, false, "")); + layoutTable.Rows.Add(this.AddTableRowTextBox("UserName attribute:", "txt" + UserNameAttributeName, 400, 100, false, "")); + layoutTable.Rows.Add(this.AddTableRowTextBox("User reference attribute:", "txt" + TargetReferenceAttributeName, 400, 100, false, "")); + layoutTable.Rows.Add(this.AddActorDropDownList("Actor (run as):", "txt" + Actor, 400, WellKnownGuids.FIMServiceAccount.ToString())); + this.Controls.Add(layoutTable); + base.CreateChildControls(); + } + + public override Activity GenerateActivityOnWorkflow(SequentialWorkflow workflow) + { + Debugging.Log("GenerateActivityOnWorkflow"); + if (!this.ValidateInputs()) + { + return null; + } + UpdateReferenceOnRegExMatchActivity act = new UpdateReferenceOnRegExMatchActivity(); + act.RegExFilter = this.GetText("txt" + RegExFilter); + act.PositiveRegExFilter = this.GetText("txt" + PositiveRegExFilter); + act.ComputerNameAttributeName = this.GetText("txt" + ComputerNameAttributeName); + act.UserNameAttributeName = this.GetText("txt" + UserNameAttributeName); + act.TargetReferenceAttributeName = this.GetText("txt" + TargetReferenceAttributeName); + act.Actor = this.GetActorDropDownList("txt" + Actor); + return act; + } + + public override void LoadActivitySettings(Activity activity) + { + Debugging.Log("LoadActivitySettings"); + UpdateReferenceOnRegExMatchActivity act = activity as UpdateReferenceOnRegExMatchActivity; + if (act != null) + { + this.SetText("txt" + RegExFilter, act.RegExFilter); + this.SetText("txt" + PositiveRegExFilter, act.PositiveRegExFilter); + this.SetText("txt" + ComputerNameAttributeName, act.ComputerNameAttributeName); + this.SetText("txt" + UserNameAttributeName, act.UserNameAttributeName); + this.SetText("txt" + TargetReferenceAttributeName, act.TargetReferenceAttributeName); + this.SetActorDropDownList("txt" + Actor, act.Actor); + } + } + + public override ActivitySettingsPartData PersistSettings() + { + Debugging.Log("PersistSettings"); + ActivitySettingsPartData data = new ActivitySettingsPartData(); + data[RegExFilter] = this.GetText("txt" + RegExFilter); + data[PositiveRegExFilter] = this.GetText("txt" + PositiveRegExFilter); + data[UserNameAttributeName] = this.GetText("txt" + UserNameAttributeName); + data[ComputerNameAttributeName] = this.GetText("txt" + ComputerNameAttributeName); + data[TargetReferenceAttributeName] = this.GetText("txt" + TargetReferenceAttributeName); + data[Actor] = this.GetActorDropDownList("txt" + Actor); + return data; + } + + public override void RestoreSettings(ActivitySettingsPartData data) + { + Debugging.Log("RestoreSettings"); + if (null != data) + { + this.SetText("txt" + RegExFilter, (string)data[RegExFilter]); + this.SetText("txt" + PositiveRegExFilter, (string)data[PositiveRegExFilter]); + this.SetText("txt" + UserNameAttributeName, (string)data[UserNameAttributeName]); + this.SetText("txt" + ComputerNameAttributeName, (string)data[ComputerNameAttributeName]); + this.SetText("txt" + TargetReferenceAttributeName, (string)data[TargetReferenceAttributeName]); + this.SetActorDropDownList("txt" + Actor, (string)data[Actor]); + } + } + + public override void SwitchMode(ActivitySettingsPartMode mode) + { + Debugging.Log("SwitchMode"); + bool isDisabled = (mode != ActivitySettingsPartMode.Edit); + this.SetTextBoxReadOnlyOption("txt" + RegExFilter, isDisabled); + this.SetTextBoxReadOnlyOption("txt" + PositiveRegExFilter, isDisabled); + this.SetTextBoxReadOnlyOption("txt" + UserNameAttributeName, isDisabled); + this.SetTextBoxReadOnlyOption("txt" + ComputerNameAttributeName, isDisabled); + this.SetTextBoxReadOnlyOption("txt" + TargetReferenceAttributeName, isDisabled); + this.SetDropDownListDisabled("txt" + Actor, isDisabled); + } + + public override string Title + { + get { return "Update Reference on regular expression match"; } + } + + public override bool ValidateInputs() + { + Debugging.Log("ValidateInputs"); + return true; + } + } +} diff --git a/Granfeldt.FIM.ActivityLibrary/Customer.UpdateReferenceOnRegExMatch/UpdateReferenceOnRegExMatchActivity.cs b/Granfeldt.FIM.ActivityLibrary/Customer.UpdateReferenceOnRegExMatch/UpdateReferenceOnRegExMatchActivity.cs new file mode 100644 index 0000000..9e8d554 --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Customer.UpdateReferenceOnRegExMatch/UpdateReferenceOnRegExMatchActivity.cs @@ -0,0 +1,259 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Collections; +using System.Linq; +using System.Workflow.ComponentModel; +using System.Workflow.ComponentModel.Design; +using System.Workflow.ComponentModel.Compiler; +using System.Workflow.ComponentModel.Serialization; +using System.Workflow.Runtime; +using System.Workflow.Activities; +using System.Workflow.Activities.Rules; +using System.Text.RegularExpressions; +using Microsoft.ResourceManagement.WebServices.WSResourceManagement; + +namespace Granfeldt.FIM.ActivityLibrary +{ + + public partial class UpdateReferenceOnRegExMatchActivity : SequenceActivity + { + + + #region Properties + + public static DependencyProperty CurrentRequestProperty = DependencyProperty.Register("CurrentRequest", typeof(RequestType), typeof(UpdateReferenceOnRegExMatchActivity)); + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] + [BrowsableAttribute(true)] + [CategoryAttribute("Misc")] + public RequestType CurrentRequest + { + get + { + return ((Microsoft.ResourceManagement.WebServices.WSResourceManagement.RequestType)(base.GetValue(Granfeldt.FIM.ActivityLibrary.UpdateReferenceOnRegExMatchActivity.CurrentRequestProperty))); + } + set + { + base.SetValue(Granfeldt.FIM.ActivityLibrary.UpdateReferenceOnRegExMatchActivity.CurrentRequestProperty, value); + } + } + + // ^w8(ab|fe)pc|[1|2|3]*[w|t]$ + public static DependencyProperty RegExFilterProperty = DependencyProperty.Register("RegExFilter", typeof(string), typeof(UpdateReferenceOnRegExMatchActivity)); + [Description("RegExFilter")] + [Category("RegExFilter Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public string RegExFilter + { + get + { + return ((string)(base.GetValue(UpdateReferenceOnRegExMatchActivity.RegExFilterProperty))); + } + set + { + base.SetValue(UpdateReferenceOnRegExMatchActivity.RegExFilterProperty, value); + } + } + + public static DependencyProperty PositiveRegExFilterProperty = DependencyProperty.Register("PositiveRegExFilter", typeof(string), typeof(UpdateReferenceOnRegExMatchActivity)); + [Description("PositiveRegExFilter")] + [Category("PositiveRegExFilter Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public string PositiveRegExFilter + { + get + { + return ((string)(base.GetValue(UpdateReferenceOnRegExMatchActivity.PositiveRegExFilterProperty))); + } + set + { + base.SetValue(UpdateReferenceOnRegExMatchActivity.PositiveRegExFilterProperty, value); + } + } + + public static DependencyProperty ComputerNameAttributeNameProperty = DependencyProperty.Register("ComputerNameAttributeName", typeof(string), typeof(UpdateReferenceOnRegExMatchActivity)); + [Description("ComputerNameAttributeName")] + [Category("ComputerNameAttributeName Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public string ComputerNameAttributeName + { + get + { + return ((string)(base.GetValue(UpdateReferenceOnRegExMatchActivity.ComputerNameAttributeNameProperty))); + } + set + { + base.SetValue(UpdateReferenceOnRegExMatchActivity.ComputerNameAttributeNameProperty, value); + } + } + + public static DependencyProperty UserNameAttributeNameProperty = DependencyProperty.Register("UserNameAttributeName", typeof(string), typeof(UpdateReferenceOnRegExMatchActivity)); + [Description("UserNameAttributeName")] + [Category("UserNameAttribute Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public string UserNameAttributeName + { + get + { + return ((string)(base.GetValue(UpdateReferenceOnRegExMatchActivity.UserNameAttributeNameProperty))); + } + set + { + base.SetValue(UpdateReferenceOnRegExMatchActivity.UserNameAttributeNameProperty, value); + } + } + + public static DependencyProperty TargetReferenceAttributeNameProperty = DependencyProperty.Register("TargetReferenceAttributeName", typeof(string), typeof(UpdateReferenceOnRegExMatchActivity)); + [Description("TargetReferenceAttributeName")] + [Category("TargetReferenceAttributeName Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public string TargetReferenceAttributeName + { + get + { + return ((string)(base.GetValue(UpdateReferenceOnRegExMatchActivity.TargetReferenceAttributeNameProperty))); + } + set + { + base.SetValue(UpdateReferenceOnRegExMatchActivity.TargetReferenceAttributeNameProperty, value); + } + } + + public static DependencyProperty TargetResourceProperty = DependencyProperty.Register("TargetResource", typeof(Microsoft.ResourceManagement.WebServices.WSResourceManagement.ResourceType), typeof(Granfeldt.FIM.ActivityLibrary.UpdateReferenceOnRegExMatchActivity)); + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] + [BrowsableAttribute(true)] + [CategoryAttribute("Parameters")] + public ResourceType TargetResource + { + get + { + return ((Microsoft.ResourceManagement.WebServices.WSResourceManagement.ResourceType)(base.GetValue(Granfeldt.FIM.ActivityLibrary.UpdateReferenceOnRegExMatchActivity.TargetResourceProperty))); + } + set + { + base.SetValue(Granfeldt.FIM.ActivityLibrary.UpdateReferenceOnRegExMatchActivity.TargetResourceProperty, value); + } + } + + public static DependencyProperty ActorProperty = DependencyProperty.Register("Actor", typeof(string), typeof(UpdateReferenceOnRegExMatchActivity)); + [Description("Actor")] + [Category("Actor Category")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public string Actor + { + get + { + return ((string)(base.GetValue(UpdateReferenceOnRegExMatchActivity.ActorProperty))); + } + set + { + base.SetValue(UpdateReferenceOnRegExMatchActivity.ActorProperty, value); + } + } + + #endregion + + public UpdateReferenceOnRegExMatchActivity() + { + InitializeComponent(); + } + + private void PrepareReadTargetCode(object sender, EventArgs e) + { + Debugging.Log("Enter PrepareReadTargetCode"); + Debugging.Log("Actor", this.Actor); + Debugging.Log("Computername attribute", this.ComputerNameAttributeName); + Debugging.Log("Usernamename attribute", this.UserNameAttributeName); + Debugging.Log("Request targetid", CurrentRequest.Target.GetGuid()); + + ReadTarget.ActorId = new Guid(this.Actor); + ReadTarget.SelectionAttributes = new string[] { this.ComputerNameAttributeName, this.UserNameAttributeName }; + ReadTarget.ResourceId = CurrentRequest.Target.GetGuid(); + ReadTarget.StatusChanged += new System.EventHandler(Activity_StatusChanged); + + Debugging.Log("Exit PrepareReadTargetCode"); + } + + void Activity_StatusChanged(object sender, ActivityExecutionStatusChangedEventArgs e) + { + Debugging.Log(string.Format("{0} {1} with result: {2}", e.ExecutionStatus, e.Activity.Name, e.ExecutionResult)); + } + + + private void IfComputerNameContainsUsername(object sender, ConditionalEventArgs e) + { + Debugging.Log("Enter IfComputerNameContainsUsername"); + + // always setup defaults for updating + UpdateUserReference.ActorId = new Guid(this.Actor); + UpdateUserReference.AttributeName = this.TargetReferenceAttributeName; + UpdateUserReference.TargetId = CurrentRequest.Target.GetGuid(); + UpdateUserReference.NewValue = null; + UpdateUserReference.StatusChanged += new System.EventHandler(Activity_StatusChanged); + + if (ReadTarget.Resource == null) + { + Debugging.Log("Could not read request target"); + e.Result = false; + return; + } + + object computername = ReadTarget.Resource[this.ComputerNameAttributeName]; + object username = ReadTarget.Resource[this.UserNameAttributeName]; + + Debugging.Log("Computername", computername); + Debugging.Log("Username", username); + + e.Result = false; + if ((username == null) || (computername == null)) + { + Debugging.Log(string.Format("{0} or {1} is null. No match", this.ComputerNameAttributeName, this.UserNameAttributeName)); + return; + } + + string computerusername = Regex.Replace(computername as string, this.RegExFilter, "", RegexOptions.IgnoreCase); + Debugging.Log("Regex trimmed computername", computerusername); + if ((computerusername.Equals(username as string, StringComparison.OrdinalIgnoreCase)) || (Regex.IsMatch(computername as string, this.PositiveRegExFilter, RegexOptions.IgnoreCase))) + { + Debugging.Log("We got a match; doing lookup for user", username); + e.Result = true; + + // set up lookup code + FindUser.ActorId = WellKnownGuids.FIMServiceAccount; + FindUser.Attributes = new string[] { "ObjectID" }; + FindUser.XPathFilter = string.Format("/Person[AccountName='{0}']", username); + FindUser.PageSize = 100; + FindUser.StatusChanged += new System.EventHandler(Activity_StatusChanged); + return; + } + Debugging.Log("Exit IfComputerNameContainsUsername"); + } + + private void PrepareUpdateReferenceCode(object sender, EventArgs e) + { + Debugging.Log("Enter PrepareUpdateReferenceCode"); + if (FindUser.TotalResultsCount == 1) + { + ResourceType r; + r = FindUser.EnumeratedResources[0]; + UpdateUserReference.NewValue = r["ObjectID"]; + } + Debugging.Log("Exit PrepareUpdateReferenceCode"); + } + + private void PrepareClearingReferenceCode(object sender, EventArgs e) + { + Debugging.Log("Enter PrepareClearingReferenceCode"); + // all setup for clearing is done in IfComputerNameContainsUsername + Debugging.Log("Exit PrepareClearingReferenceCode"); + } + + } + +} diff --git a/Granfeldt.FIM.ActivityLibrary/Granfeldt.FIM.ActivityLibrary.csproj b/Granfeldt.FIM.ActivityLibrary/Granfeldt.FIM.ActivityLibrary.csproj index 911b566..14812d9 100644 --- a/Granfeldt.FIM.ActivityLibrary/Granfeldt.FIM.ActivityLibrary.csproj +++ b/Granfeldt.FIM.ActivityLibrary/Granfeldt.FIM.ActivityLibrary.csproj @@ -36,23 +36,19 @@ False - .\Microsoft.IdentityManagement.Activities.dll - - - ..\..\..\..\..\..\Program Files\Microsoft Forefront Identity Manager\2010\Service\Microsoft.IdentityManagement.SettingsContract.dll - False + FIMDLLs\Microsoft.IdentityManagement.Activities.dll False - .\Microsoft.IdentityManagement.WebUI.Controls.dll + FIMDLLs\Microsoft.IdentityManagement.WebUI.Controls.dll False - .\Microsoft.IdentityManagement.WFExtensionInterfaces.dll + FIMDLLs\Microsoft.IdentityManagement.WFExtensionInterfaces.dll False - ..\..\..\..\..\..\Program Files\Microsoft Forefront Identity Manager\2010\Service\Microsoft.ResourceManagement.dll + FIMDLLs\Microsoft.ResourceManagement.dll @@ -68,6 +64,20 @@ + + Component + + + Activity.AddRemoveFromMultiValue.cs + + + + Component + + + Activity.ClearSingleValuedAttribute.cs + + Component @@ -108,6 +118,12 @@ + + Component + + + Helper.AddRemoveMultiValueAsNeededActivity.cs + Component @@ -126,6 +142,7 @@ True Settings.settings + Always diff --git a/Granfeldt.FIM.ActivityLibrary/Install-Workflows.ps1 b/Granfeldt.FIM.ActivityLibrary/Install-Workflows.ps1 index 5eecca2..86fc6b4 100644 --- a/Granfeldt.FIM.ActivityLibrary/Install-Workflows.ps1 +++ b/Granfeldt.FIM.ActivityLibrary/Install-Workflows.ps1 @@ -1,5 +1,7 @@ # January 30, 2013 | Soren Granfeldt # - changed LookupAttributeValue to LookupValueActivity +# december 16, 2015 | soren granfeldt +# - added ClearSingleValueActivity PARAM ( @@ -8,6 +10,7 @@ PARAM [switch] $CreateLookupValueActivity, [switch] $CreateCopyValuesActivity, [switch] $CreateCreateObjectActivity, + [switch] $CreateClearSingleValueActivity, [switch] $CreateDeleteObjectActivity ) @@ -95,6 +98,19 @@ PROCESS .\New-FIMActivityInformationConfigurationObject.ps1 @Params } + if ($CreateClearSingleValueActivity) + { + $Params = @{ ` + DisplayName = 'Clear Single Value' + Description = 'Clears a single value attribute' + ActivityName = "$ManifestModule.ClearSingleValuedAttributeActivity" + TypeName = "$ManifestModule.WebUIs.ClearSingleValuedAttributeActivitySettingsPart" + IsActionActivity = $true + AssemblyName = $LoadedAssembly.Fullname + } + $Params + .\New-FIMActivityInformationConfigurationObject.ps1 @Params + } } END diff --git a/Granfeldt.FIM.ActivityLibrary/Properties/AssemblyInfo.cs b/Granfeldt.FIM.ActivityLibrary/Properties/AssemblyInfo.cs index aec7822..b81fddc 100644 --- a/Granfeldt.FIM.ActivityLibrary/Properties/AssemblyInfo.cs +++ b/Granfeldt.FIM.ActivityLibrary/Properties/AssemblyInfo.cs @@ -30,4 +30,4 @@ using System.Runtime.InteropServices; //NOTE: When updating the namespaces in the project please add new or update existing the XmlnsDefinitionAttribute //You can add additional attributes in order to map any additional namespaces you have in the project //[assembly: System.Workflow.ComponentModel.Serialization.XmlnsDefinition("http://schemas.com/Granfeldt.FIM.ActivityLibrary", "Granfeldt.FIM.ActivityLibrary")] -[assembly: AssemblyFileVersionAttribute("1.5.0.0")] +[assembly: AssemblyFileVersion("1.6.0.1612")] diff --git a/Granfeldt.FIM.ActivityLibrary/Tracer.cs b/Granfeldt.FIM.ActivityLibrary/Tracer.cs new file mode 100644 index 0000000..d8f68f1 --- /dev/null +++ b/Granfeldt.FIM.ActivityLibrary/Tracer.cs @@ -0,0 +1,75 @@ +using System; +using System.Diagnostics; +using System.Text; + +namespace Granfeldt.FIM.ActivityLibrary +{ + public static class Tracer + { + //TODO: convert ident to stringbuilder + const string SwitchName = "WFL"; + const string SourceName = "WFL"; + public static TraceSource Trace = new TraceSource(SourceName, SourceLevels.All); + static string IndentText = ""; + + public static int IndentLevel + { + get + { + return IndentText.Length; + } + set + { + IndentText = ""; + } + } + public static void Indent() + { + IndentText = IndentText + " "; + } + public static void Unindent() + { + IndentText = IndentText.EndsWith(" ") ? IndentText.Remove(IndentText.Length - 2) : IndentText; + } + public static void Enter(string entryPoint) + { + TraceInformation("enter {0}", entryPoint); + Indent(); + //Process currentProc = Process.GetCurrentProcess(); + //Tracer.TraceInformation("memory-usage {0:n0}Kb, private memomry {1:n0}Kb", GC.GetTotalMemory(true) / 1024, currentProc.PrivateMemorySize64 / 1024); + } + public static void Exit(string entryPoint) + { + //Process currentProc = Process.GetCurrentProcess(); + //Tracer.TraceInformation("memory-usage {0:n0}Kb, private memory {1:n0}Kb", GC.GetTotalMemory(true) / 1024, currentProc.PrivateMemorySize64 / 1024); + Unindent(); + TraceInformation("exit {0}", entryPoint); + } + public static void TraceInformation(string message, params object[] param) + { + Trace.TraceInformation(IndentText + message, param); + } + public static void TraceWarning(string message, params object[] param) + { + Trace.TraceEvent(TraceEventType.Warning, -1, IndentText + message, param); + } + public static void TraceError(string message, int id, params object[] param) + { + Trace.TraceEvent(TraceEventType.Error, id, IndentText + message, param); + } + public static void TraceError(string message, Exception ex) + { + Trace.TraceEvent(TraceEventType.Error, ex.GetHashCode(), IndentText + "{0}, {1}", message, ex.Message); + } + public static void TraceError(string message, params object[] param) + { + TraceError(message, -2, param); + } + static Tracer() + { + SourceSwitch sw = new SourceSwitch(SwitchName, SwitchName); + sw.Level = SourceLevels.All; + Trace.Switch = sw; + } + } +}