/// <summary>
        /// Returns the field's current value(s)
        /// </summary>
        /// <param name="parentControl">The parent control.</param>
        /// <param name="value">Information about the value</param>
        /// <param name="configurationValues">The configuration values.</param>
        /// <param name="condensed">Flag indicating if the value should be condensed (i.e. for use in a grid column)</param>
        /// <returns></returns>
        public override string FormatValue( Control parentControl, string value, Dictionary<string, ConfigurationValue> configurationValues, bool condensed )
        {
            string formattedValue = string.Empty;

            Guid guid = value.AsGuid();
            if ( !guid.IsEmpty() )
            {
                var workflowType = GetContextWorkflowType();
                if ( workflowType != null )
                {
                    formattedValue = workflowType.ActivityTypes
                        .Where( a => a.Guid.Equals( guid ) )
                        .Select( a => a.Name )
                        .FirstOrDefault();
                }

                if ( string.IsNullOrWhiteSpace( formattedValue ) )
                {
                    formattedValue = new WorkflowActivityTypeService( new RockContext() ).Queryable()
                        .Where( a => a.Guid.Equals( guid ) )
                        .Select( a => a.Name )
                        .FirstOrDefault();
                }
            }

            return base.FormatValue( parentControl, formattedValue, null, condensed );

        }
예제 #2
0
        /// <summary>
        /// Executes the specified workflow.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="action">The action.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        public override bool Execute( RockContext rockContext, WorkflowAction action, Object entity, out List<string> errorMessages )
        {
            errorMessages = new List<string>();

            Guid guid = GetAttributeValue( action, "Activity" ).AsGuid();
            if ( guid.IsEmpty() )
            {
                action.AddLogEntry( "Invalid Activity Property", true );
                return false;
            }

            var workflow = action.Activity.Workflow;

            var activityType = new WorkflowActivityTypeService( rockContext ).Queryable()
                .Where( a => a.Guid.Equals( guid ) ).FirstOrDefault();

            if ( activityType == null )
            {
                action.AddLogEntry( "Invalid Activity Property", true );
                return false;
            }

            WorkflowActivity.Activate( activityType, workflow );
            action.AddLogEntry( string.Format( "Activated new '{0}' activity", activityType.ToString() ) );

            return true;
        }
        /// <summary>
        /// Executes the specified workflow.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="action">The action.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        public override bool Execute( RockContext rockContext, WorkflowAction action, Object entity, out List<string> errorMessages )
        {
            errorMessages = new List<string>();

            var workflowActivityGuid = action.GetWorklowAttributeValue( GetAttributeValue( action, "Activity" ).AsGuid() ).AsGuid();
            if ( workflowActivityGuid.IsEmpty() )
            {
                action.AddLogEntry( "Invalid Activity Property", true );
                return false;
            }

            var attributeKey = GetAttributeValue( action, "WorkflowAttributeKey", true );
            var attributeValue = GetAttributeValue( action, "WorkflowAttributeValue", true );
            if ( string.IsNullOrWhiteSpace( attributeKey) || string.IsNullOrWhiteSpace(attributeValue) )
            {
                action.AddLogEntry( "Invalid Workflow Property", true );
                return false;
            }

            var activityType = new WorkflowActivityTypeService( rockContext ).Queryable()
                .Where( a => a.Guid.Equals( workflowActivityGuid ) ).FirstOrDefault();

            if ( activityType == null )
            {
                action.AddLogEntry( "Invalid Activity Property", true );
                return false;
            }

            var entityType = EntityTypeCache.Read( typeof( Rock.Model.Workflow ) );

            var workflowIds = new AttributeValueService( rockContext )
                .Queryable()
                .AsNoTracking()
                .Where( a => a.Attribute.Key == attributeKey && a.Value == attributeValue && a.Attribute.EntityTypeId == entityType.Id )
                .Select(a => a.EntityId);

            var workflows = new WorkflowService( rockContext )
                .Queryable()
                //.AsNoTracking()
                .Where( w => w.WorkflowType.ActivityTypes.Any( a => a.Guid == activityType.Guid ) && workflowIds.Contains(w.Id) )
                .ToList();

            foreach (var workflow in workflows )
            {
                WorkflowActivity.Activate( activityType, workflow );
                action.AddLogEntry( string.Format( "Activated new '{0}' activity in {1} {2}", activityType.ToString(), workflow.TypeName, workflow.WorkflowId ) );
            }

            return true;
        }
        /// <summary>
        /// Creates the control(s) necessary for prompting user for a new value
        /// </summary>
        /// <param name="configurationValues">The configuration values.</param>
        /// <param name="id"></param>
        /// <returns>
        /// The control
        /// </returns>
        public override Control EditControl( Dictionary<string, ConfigurationValue> configurationValues, string id )
        {
            ListControl editControl;

            editControl = new Rock.Web.UI.Controls.RockDropDownList { ID = id };
            editControl.Items.Add( new ListItem() );

            IEnumerable<WorkflowActivityType> activityTypes = null;

            var workflowType = GetContextWorkflowType();
            if ( workflowType != null )
            {
                activityTypes = workflowType.ActivityTypes;
            }

            if (activityTypes == null && configurationValues != null && configurationValues.ContainsKey( WORKFLOW_TYPE_KEY ) )
            {
                Guid workflowTypeGuid = configurationValues[WORKFLOW_TYPE_KEY].Value.AsGuid();
                if ( !workflowTypeGuid.IsEmpty() )
                {
                    activityTypes = new WorkflowActivityTypeService( new RockContext() )
                        .Queryable()
                        .Where( t => t.WorkflowType.Guid.Equals( workflowTypeGuid ) );
                }
            }

            if (activityTypes != null && activityTypes.Any() )
            {
                foreach ( var activityType in activityTypes.OrderBy( a => a.Order ) )
                {
                    editControl.Items.Add( new ListItem( activityType.Name ?? "[New Activity]", activityType.Guid.ToString().ToUpper() ) );
                }
            }

            return editControl;
        }
        /// <summary>
        /// Restores the view-state information from a previous user control request that was saved by the <see cref="M:System.Web.UI.UserControl.SaveViewState" /> method.
        /// </summary>
        /// <param name="savedState">An <see cref="T:System.Object" /> that represents the user control state to be restored.</param>
        protected override void LoadViewState( object savedState )
        {
            base.LoadViewState( savedState );

            string json = ViewState["Workflow"] as string;
            if ( string.IsNullOrWhiteSpace( json ) )
            {
                Workflow = new Workflow();
            }
            else
            {
                Workflow = JsonConvert.DeserializeObject<Workflow>( json );
            }

            // Wire up type objects since they are not serialized
            var rockContext = new RockContext();
            var workflowTypeService = new WorkflowTypeService( rockContext );
            var activityTypeService = new WorkflowActivityTypeService( rockContext );
            var actionTypeService = new WorkflowActionTypeService( rockContext );
            Workflow.WorkflowType = workflowTypeService.Get( Workflow.WorkflowTypeId );
            foreach(var activity in Workflow.Activities)
            {
                activity.ActivityType = activityTypeService.Get( activity.ActivityTypeId );
                foreach(var action in activity.Actions)
                {
                    action.ActionType = actionTypeService.Get( action.ActionTypeId );
                }
            }

            // Add new log entries since they are not serialized
            LogEntries = ViewState["LogEntries"] as List<string>;
            if ( LogEntries == null )
            {
                LogEntries = new List<string>();
            }
            LogEntries.ForEach( l => Workflow.AddLogEntry( l ) );

            ExpandedActivities = ViewState["ExpandedActivities"] as List<Guid>;
            if (ExpandedActivities == null)
            {
                ExpandedActivities = new List<Guid>();
            }
        }
        protected void ddlActivateNewActivity_SelectedIndexChanged( object sender, EventArgs e )
        {
            ParseControls();

            int? activityTypeId = ddlActivateNewActivity.SelectedValueAsId();
            if (activityTypeId.HasValue)
            {
                var activityType = new WorkflowActivityTypeService(new RockContext()).Get(activityTypeId.Value);
                if (activityType != null)
                {
                    var activity = WorkflowActivity.Activate( activityType, Workflow );
                    activity.ActivityTypeId = activity.ActivityType.Id;
                    activity.Guid = Guid.NewGuid();

                    foreach( var action in activity.Actions)
                    {
                        action.ActionTypeId = action.ActionType.Id;
                        action.Guid = Guid.NewGuid();
                    }

                    Workflow.AddLogEntry( string.Format( "Manually Activated new '{0}' activity", activityType.ToString() ) );

                    ExpandedActivities.Add( activity.Guid );

                    BuildControls( true, activity.Guid );
                }
            }

            ddlActivateNewActivity.SelectedIndex = 0;
        }
        /// <summary>
        /// Handles the Click event of the btnSave control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
        protected void btnSave_Click( object sender, EventArgs e )
        {
            var rockContext = new RockContext();

            WorkflowType workflowType;
            WorkflowTypeService service = new WorkflowTypeService( rockContext );

            int workflowTypeId = int.Parse( hfWorkflowTypeId.Value );

            if ( workflowTypeId == 0 )
            {
                workflowType = new WorkflowType();
                workflowType.IsSystem = false;
                workflowType.Name = string.Empty;
            }
            else
            {
                workflowType = service.Get( workflowTypeId );
            }

            workflowType.Name = tbName.Text;
            workflowType.Description = tbDescription.Text;
            workflowType.CategoryId = cpCategory.SelectedValueAsInt();
            workflowType.Order = 0;
            workflowType.WorkTerm = tbWorkTerm.Text;
            if ( !string.IsNullOrWhiteSpace( tbProcessingInterval.Text ) )
            {
                workflowType.ProcessingIntervalSeconds = int.Parse( tbProcessingInterval.Text );
            }

            workflowType.IsPersisted = cbIsPersisted.Checked;
            workflowType.LoggingLevel = ddlLoggingLevel.SelectedValueAsEnum<WorkflowLoggingLevel>();
            workflowType.IsActive = cbIsActive.Checked;

            if ( !Page.IsValid )
            {
                return;
            }

            if ( !workflowType.IsValid )
            {
                // Controls will render the error messages
                return;
            }

            RockTransactionScope.WrapTransaction( () =>
            {
                // Save the entity field changes to workflow type
                if ( workflowType.Id.Equals( 0 ) )
                {
                    service.Add( workflowType );
                }
                rockContext.SaveChanges();

                // Save the attributes
                SaveAttributes( new Workflow().TypeId, "WorkflowTypeId", workflowType.Id.ToString(), AttributesState, rockContext );

                WorkflowActivityTypeService workflowActivityTypeService = new WorkflowActivityTypeService( rockContext );
                WorkflowActionTypeService workflowActionTypeService = new WorkflowActionTypeService( rockContext );
                WorkflowActionFormService workflowFormService = new WorkflowActionFormService( rockContext );
                WorkflowActionFormAttributeService workflowFormAttributeService = new WorkflowActionFormAttributeService( rockContext );

                // delete WorkflowActionTypes that aren't assigned in the UI anymore
                List<WorkflowActivityEditor> workflowActivityTypeEditorList = phActivities.Controls.OfType<WorkflowActivityEditor>().ToList();
                List<WorkflowActionType> actionTypesInDB = workflowActionTypeService.Queryable().Where( a => a.ActivityType.WorkflowTypeId.Equals( workflowType.Id ) ).ToList();
                List<WorkflowActionType> actionTypesInUI = new List<WorkflowActionType>();
                foreach ( WorkflowActivityEditor workflowActivityTypeEditor in workflowActivityTypeEditorList )
                {
                    foreach ( WorkflowActionEditor editor in workflowActivityTypeEditor.Controls.OfType<WorkflowActionEditor>() )
                    {
                        actionTypesInUI.Add( editor.WorkflowActionType );
                    }
                }
                var deletedActionTypes = from actionType in actionTypesInDB
                                         where !actionTypesInUI.Select( u => u.Guid ).Contains( actionType.Guid )
                                         select actionType;
                deletedActionTypes.ToList().ForEach( actionType =>
                {
                    if (actionType.WorkflowForm != null)
                    {
                        workflowFormService.Delete( actionType.WorkflowForm );
                    }
                    workflowActionTypeService.Delete( actionType );
                } );
                rockContext.SaveChanges();

                // delete WorkflowActivityTypes that aren't assigned in the UI anymore
                List<WorkflowActivityType> activityTypesInDB = workflowActivityTypeService.Queryable().Where( a => a.WorkflowTypeId.Equals( workflowType.Id ) ).ToList();
                List<WorkflowActivityType> activityTypesInUI = workflowActivityTypeEditorList.Select( a => a.GetWorkflowActivityType() ).ToList();
                var deletedActivityTypes = from activityType in activityTypesInDB
                                           where !activityTypesInUI.Select( u => u.Guid ).Contains( activityType.Guid )
                                           select activityType;
                deletedActivityTypes.ToList().ForEach( activityType =>
                {
                    workflowActivityTypeService.Delete( activityType );
                } );
                rockContext.SaveChanges();

                // add or update WorkflowActivityTypes(and Actions) that are assigned in the UI
                int workflowActivityTypeOrder = 0;
                foreach ( WorkflowActivityEditor workflowActivityTypeEditor in workflowActivityTypeEditorList )
                {
                    // Add or Update the activity type
                    WorkflowActivityType editorWorkflowActivityType = workflowActivityTypeEditor.GetWorkflowActivityType();
                    WorkflowActivityType workflowActivityType = workflowType.ActivityTypes.FirstOrDefault( a => a.Guid.Equals( editorWorkflowActivityType.Guid ) );
                    if ( workflowActivityType == null )
                    {
                        workflowActivityType = new WorkflowActivityType();
                        workflowType.ActivityTypes.Add( workflowActivityType );

                    }
                    workflowActivityType.IsActive = editorWorkflowActivityType.IsActive;
                    workflowActivityType.Name = editorWorkflowActivityType.Name;
                    workflowActivityType.Description = editorWorkflowActivityType.Description;
                    workflowActivityType.IsActivatedWithWorkflow = editorWorkflowActivityType.IsActivatedWithWorkflow;
                    workflowActivityType.Order = workflowActivityTypeOrder++;

                    int workflowActionTypeOrder = 0;
                    foreach ( WorkflowActionEditor workflowActionTypeEditor in workflowActivityTypeEditor.Controls.OfType<WorkflowActionEditor>() )
                    {
                        WorkflowActionType editorWorkflowActionType = workflowActionTypeEditor.WorkflowActionType;
                        WorkflowActionType workflowActionType = workflowActivityType.ActionTypes.FirstOrDefault( a => a.Guid.Equals( editorWorkflowActionType.Guid ) );
                        if ( workflowActionType == null )
                        {
                            // New action
                            workflowActionType = new WorkflowActionType();
                            workflowActivityType.ActionTypes.Add( workflowActionType );
                        }
                        workflowActionType.Name = editorWorkflowActionType.Name;
                        workflowActionType.EntityTypeId = editorWorkflowActionType.EntityTypeId;
                        workflowActionType.IsActionCompletedOnSuccess = editorWorkflowActionType.IsActionCompletedOnSuccess;
                        workflowActionType.IsActivityCompletedOnSuccess = editorWorkflowActionType.IsActivityCompletedOnSuccess;
                        workflowActionType.Attributes = editorWorkflowActionType.Attributes;
                        workflowActionType.AttributeValues = editorWorkflowActionType.AttributeValues;
                        workflowActionType.Order = workflowActionTypeOrder++;

                        if ( workflowActionType.WorkflowForm != null && editorWorkflowActionType.WorkflowForm == null )
                        {
                            // Form removed
                            workflowFormService.Delete( workflowActionType.WorkflowForm );
                            workflowActionType.WorkflowForm = null;
                        }

                        if (editorWorkflowActionType.WorkflowForm != null)
                        {
                            if (workflowActionType.WorkflowForm == null)
                            {
                                workflowActionType.WorkflowForm = new WorkflowActionForm();
                            }

                            workflowActionType.WorkflowForm.Header = editorWorkflowActionType.WorkflowForm.Header;
                            workflowActionType.WorkflowForm.Footer = editorWorkflowActionType.WorkflowForm.Footer;
                            workflowActionType.WorkflowForm.InactiveMessage = editorWorkflowActionType.WorkflowForm.InactiveMessage;
                            workflowActionType.WorkflowForm.Actions = editorWorkflowActionType.WorkflowForm.Actions;

                            var editorGuids = editorWorkflowActionType.WorkflowForm.FormAttributes
                                .Select( a => a.Attribute.Guid)
                                .ToList();

                            foreach( var formAttribute in workflowActionType.WorkflowForm.FormAttributes
                                .Where( a => !editorGuids.Contains(a.Attribute.Guid) ) )
                            {
                                workflowFormAttributeService.Delete(formAttribute);
                            }

                            int attributeOrder = 0;
                            foreach ( var editorAttribute in editorWorkflowActionType.WorkflowForm.FormAttributes.OrderBy( a => a.Order ) )
                            {
                                int attributeId = AttributeCache.Read( editorAttribute.Attribute.Guid ).Id;

                                var formAttribute = workflowActionType.WorkflowForm.FormAttributes
                                    .Where( a => a.AttributeId == attributeId )
                                    .FirstOrDefault();

                                if (formAttribute == null)
                                {
                                    formAttribute = new WorkflowActionFormAttribute();
                                    formAttribute.Guid = editorAttribute.Guid;
                                    formAttribute.AttributeId = attributeId;
                                    workflowActionType.WorkflowForm.FormAttributes.Add( formAttribute );
                                }

                                formAttribute.Order = attributeOrder++;
                                formAttribute.IsVisible = editorAttribute.IsVisible;
                                formAttribute.IsReadOnly = editorAttribute.IsReadOnly;
                                formAttribute.IsRequired = editorAttribute.IsRequired;
                            }
                        }
                    }
                }

                rockContext.SaveChanges();

                foreach ( var activityType in workflowType.ActivityTypes )
                {
                    foreach ( var workflowActionType in activityType.ActionTypes )
                    {
                        workflowActionType.SaveAttributeValues( rockContext );
                    }
                }

            } );

            var qryParams = new Dictionary<string, string>();
            qryParams["workflowTypeId"] = workflowType.Id.ToString();
            NavigateToPage( RockPage.Guid, qryParams );
        }
예제 #8
0
        /// <summary>
        /// Handles the Click event of the btnSave control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
        protected void btnSave_Click( object sender, EventArgs e )
        {
            ParseControls( true );

            var rockContext = new RockContext();
            var service = new WorkflowTypeService( rockContext );

            WorkflowType workflowType = null;

            int? workflowTypeId = hfWorkflowTypeId.Value.AsIntegerOrNull();
            if ( workflowTypeId.HasValue )
            {
                workflowType = service.Get( workflowTypeId.Value );
            }

            if ( workflowType == null )
            {
                workflowType = new WorkflowType();
            }

            var validationErrors = new List<string>();

            // check for unique prefix
            string prefix = tbNumberPrefix.UntrimmedText;
            if ( !string.IsNullOrWhiteSpace( prefix ) &&
                prefix.ToUpper() != ( workflowType.WorkflowIdPrefix ?? string.Empty ).ToUpper() )
            {
                if ( service.Queryable().AsNoTracking()
                    .Any( w =>
                        w.Id != workflowType.Id &&
                        w.WorkflowIdPrefix == prefix ) )
                {
                    validationErrors.Add( "Workflow Number Prefix is already being used by another workflow type.  Please use a unique prefix." );
                }
                else
                {
                    workflowType.WorkflowIdPrefix = prefix;
                }
            }
            else
            {
                workflowType.WorkflowIdPrefix = prefix;
            }

            workflowType.IsActive = cbIsActive.Checked;
            workflowType.Name = tbName.Text;
            workflowType.Description = tbDescription.Text;
            workflowType.CategoryId = cpCategory.SelectedValueAsInt();
            workflowType.WorkTerm = tbWorkTerm.Text;
            workflowType.ModifiedByPersonAliasId = CurrentPersonAliasId;
            workflowType.ModifiedDateTime = RockDateTime.Now;

            int? mins = tbProcessingInterval.Text.AsIntegerOrNull();
            if ( mins.HasValue )
            {
                workflowType.ProcessingIntervalSeconds = mins.Value * 60;
            }
            else
            {
                workflowType.ProcessingIntervalSeconds = null;
            }

            workflowType.IsPersisted = cbIsPersisted.Checked;
            workflowType.LoggingLevel = ddlLoggingLevel.SelectedValueAsEnum<WorkflowLoggingLevel>();
            workflowType.IconCssClass = tbIconCssClass.Text;
            workflowType.SummaryViewText = ceSummaryViewText.Text;
            workflowType.NoActionMessage = ceNoActionMessage.Text;

            if ( validationErrors.Any() )
            {
                nbValidationError.Text = string.Format( "Please Correct the Following<ul><li>{0}</li></ul>",
                    validationErrors.AsDelimited( "</li><li>" ) );
                nbValidationError.Visible = true;

                return;
            }

            if ( !Page.IsValid || !workflowType.IsValid )
            {
                return;
            }

            foreach(var activityType in ActivityTypesState)
            {
                if (!activityType.IsValid)
                {
                    return;
                }
                foreach(var actionType in activityType.ActionTypes)
                {
                    if ( !actionType.IsValid )
                    {
                        return;
                    }
                }
            }

            rockContext.WrapTransaction( () =>
            {
                // Save the entity field changes to workflow type
                if ( workflowType.Id.Equals( 0 ) )
                {
                    service.Add( workflowType );
                }
                rockContext.SaveChanges();

                // Save the workflow type attributes
                SaveAttributes( new Workflow().TypeId, "WorkflowTypeId", workflowType.Id.ToString(), AttributesState, rockContext );

                WorkflowActivityTypeService workflowActivityTypeService = new WorkflowActivityTypeService( rockContext );
                WorkflowActivityService workflowActivityService = new WorkflowActivityService( rockContext );
                WorkflowActionService workflowActionService = new WorkflowActionService( rockContext );
                WorkflowActionTypeService workflowActionTypeService = new WorkflowActionTypeService( rockContext );
                WorkflowActionFormService workflowFormService = new WorkflowActionFormService( rockContext );
                WorkflowActionFormAttributeService workflowFormAttributeService = new WorkflowActionFormAttributeService( rockContext );

                // delete WorkflowActionTypes that aren't assigned in the UI anymore
                List<WorkflowActionType> actionTypesInDB = workflowActionTypeService.Queryable().Where( a => a.ActivityType.WorkflowTypeId.Equals( workflowType.Id ) ).ToList();
                List<WorkflowActionType> actionTypesInUI = new List<WorkflowActionType>();

                foreach ( var workflowActivity in ActivityTypesState )
                {
                    foreach ( var workflowAction in workflowActivity.ActionTypes )
                    {
                        actionTypesInUI.Add( workflowAction );
                    }
                }

                var deletedActionTypes = from actionType in actionTypesInDB
                                         where !actionTypesInUI.Select( u => u.Guid ).Contains( actionType.Guid )
                                         select actionType;
                foreach ( var actionType in deletedActionTypes.ToList() )
                {
                    if ( actionType.WorkflowForm != null )
                    {
                        workflowFormService.Delete( actionType.WorkflowForm );
                    }

                    // Delete any workflow actions of this type
                    int loopCounter = 0;
                    foreach ( var action in workflowActionService.Queryable().Where( a => a.ActionTypeId == actionType.Id ) )
                    {
                        workflowActionService.Delete( action );
                        loopCounter++;
                        if ( loopCounter > 100 )
                        {
                            rockContext.SaveChanges();
                            loopCounter = 0;
                        }
                    }
                    rockContext.SaveChanges();

                    workflowActionTypeService.Delete( actionType );
                }
                rockContext.SaveChanges();

                // delete WorkflowActivityTypes that aren't assigned in the UI anymore
                List<WorkflowActivityType> activityTypesInDB = workflowActivityTypeService.Queryable().Where( a => a.WorkflowTypeId.Equals( workflowType.Id ) ).ToList();
                var deletedActivityTypes = from activityType in activityTypesInDB
                                           where !ActivityTypesState.Select( u => u.Guid ).Contains( activityType.Guid )
                                           select activityType;
                foreach ( var activityType in deletedActivityTypes.ToList() )
                {
                    // Delete any workflow activities of this type
                    int loopCounter = 0;
                    foreach ( var activity in workflowActivityService.Queryable().Where( a => a.ActivityTypeId == activityType.Id ) )
                    {
                        workflowActivityService.Delete( activity );
                        loopCounter++;
                        if ( loopCounter > 100 )
                        {
                            rockContext.SaveChanges();
                            loopCounter = 0;
                        }
                    }
                    rockContext.SaveChanges();

                    workflowActivityTypeService.Delete( activityType );
                }
                rockContext.SaveChanges();

                // add or update WorkflowActivityTypes(and Actions) that are assigned in the UI
                int workflowActivityTypeOrder = 0;
                foreach ( var editorWorkflowActivityType in ActivityTypesState )
                {
                    // Add or Update the activity type
                    WorkflowActivityType workflowActivityType = workflowType.ActivityTypes.FirstOrDefault( a => a.Guid.Equals( editorWorkflowActivityType.Guid ) );
                    if ( workflowActivityType == null )
                    {
                        workflowActivityType = new WorkflowActivityType();
                        workflowActivityType.Guid = editorWorkflowActivityType.Guid;
                        workflowType.ActivityTypes.Add( workflowActivityType );
                    }
                    workflowActivityType.IsActive = editorWorkflowActivityType.IsActive;
                    workflowActivityType.Name = editorWorkflowActivityType.Name;
                    workflowActivityType.Description = editorWorkflowActivityType.Description;
                    workflowActivityType.IsActivatedWithWorkflow = editorWorkflowActivityType.IsActivatedWithWorkflow;
                    workflowActivityType.Order = workflowActivityTypeOrder++;

                    // Save Activity Type
                    rockContext.SaveChanges();

                    // Save ActivityType Attributes
                    if ( ActivityAttributesState.ContainsKey( workflowActivityType.Guid ) )
                    {
                        SaveAttributes( new WorkflowActivity().TypeId, "ActivityTypeId", workflowActivityType.Id.ToString(), ActivityAttributesState[workflowActivityType.Guid], rockContext );
                    }

                    // Because the SaveAttributes above may have flushed the cached entity attribute cache, and it would get loaded again with
                    // a different context, manually reload the cache now with our context to prevent a database lock conflict (when database is
                    // configured without snapshot isolation turned on)
                    AttributeCache.LoadEntityAttributes( rockContext );

                    int workflowActionTypeOrder = 0;
                    foreach ( var editorWorkflowActionType in editorWorkflowActivityType.ActionTypes )
                    {
                        WorkflowActionType workflowActionType = workflowActivityType.ActionTypes.FirstOrDefault( a => a.Guid.Equals( editorWorkflowActionType.Guid ) );
                        if ( workflowActionType == null )
                        {
                            // New action
                            workflowActionType = new WorkflowActionType();
                            workflowActionType.Guid = editorWorkflowActionType.Guid;
                            workflowActivityType.ActionTypes.Add( workflowActionType );
                        }
                        workflowActionType.CriteriaAttributeGuid = editorWorkflowActionType.CriteriaAttributeGuid;
                        workflowActionType.CriteriaComparisonType = editorWorkflowActionType.CriteriaComparisonType;
                        workflowActionType.CriteriaValue = editorWorkflowActionType.CriteriaValue;
                        workflowActionType.Name = editorWorkflowActionType.Name;
                        workflowActionType.EntityTypeId = editorWorkflowActionType.EntityTypeId;
                        workflowActionType.IsActionCompletedOnSuccess = editorWorkflowActionType.IsActionCompletedOnSuccess;
                        workflowActionType.IsActivityCompletedOnSuccess = editorWorkflowActionType.IsActivityCompletedOnSuccess;
                        workflowActionType.Attributes = editorWorkflowActionType.Attributes;
                        workflowActionType.AttributeValues = editorWorkflowActionType.AttributeValues;
                        workflowActionType.Order = workflowActionTypeOrder++;

                        if ( workflowActionType.WorkflowForm != null && editorWorkflowActionType.WorkflowForm == null )
                        {
                            // Form removed
                            workflowFormService.Delete( workflowActionType.WorkflowForm );
                            workflowActionType.WorkflowForm = null;
                        }

                        if ( editorWorkflowActionType.WorkflowForm != null )
                        {
                            if ( workflowActionType.WorkflowForm == null )
                            {
                                workflowActionType.WorkflowForm = new WorkflowActionForm();
                            }

                            workflowActionType.WorkflowForm.NotificationSystemEmailId = editorWorkflowActionType.WorkflowForm.NotificationSystemEmailId;
                            workflowActionType.WorkflowForm.IncludeActionsInNotification = editorWorkflowActionType.WorkflowForm.IncludeActionsInNotification;
                            workflowActionType.WorkflowForm.AllowNotes = editorWorkflowActionType.WorkflowForm.AllowNotes;
                            workflowActionType.WorkflowForm.Header = editorWorkflowActionType.WorkflowForm.Header;
                            workflowActionType.WorkflowForm.Footer = editorWorkflowActionType.WorkflowForm.Footer;
                            workflowActionType.WorkflowForm.Actions = editorWorkflowActionType.WorkflowForm.Actions;
                            workflowActionType.WorkflowForm.ActionAttributeGuid = editorWorkflowActionType.WorkflowForm.ActionAttributeGuid;

                            var editorGuids = editorWorkflowActionType.WorkflowForm.FormAttributes
                                .Select( a => a.Attribute.Guid )
                                .ToList();

                            foreach ( var formAttribute in workflowActionType.WorkflowForm.FormAttributes
                                .Where( a => !editorGuids.Contains( a.Attribute.Guid ) ).ToList() )
                            {
                                workflowFormAttributeService.Delete( formAttribute );
                            }

                            int attributeOrder = 0;
                            foreach ( var editorAttribute in editorWorkflowActionType.WorkflowForm.FormAttributes.OrderBy( a => a.Order ) )
                            {
                                int attributeId = AttributeCache.Read( editorAttribute.Attribute.Guid, rockContext ).Id;

                                var formAttribute = workflowActionType.WorkflowForm.FormAttributes
                                    .Where( a => a.AttributeId == attributeId )
                                    .FirstOrDefault();

                                if ( formAttribute == null )
                                {
                                    formAttribute = new WorkflowActionFormAttribute();
                                    formAttribute.Guid = editorAttribute.Guid;
                                    formAttribute.AttributeId = attributeId;
                                    workflowActionType.WorkflowForm.FormAttributes.Add( formAttribute );
                                }

                                formAttribute.Order = attributeOrder++;
                                formAttribute.IsVisible = editorAttribute.IsVisible;
                                formAttribute.IsReadOnly = editorAttribute.IsReadOnly;
                                formAttribute.IsRequired = editorAttribute.IsRequired;
                                formAttribute.HideLabel = editorAttribute.HideLabel;
                                formAttribute.PreHtml = editorAttribute.PreHtml;
                                formAttribute.PostHtml = editorAttribute.PostHtml;
                            }
                        }
                    }
                }

                rockContext.SaveChanges();

                foreach ( var activityType in workflowType.ActivityTypes )
                {
                    foreach ( var workflowActionType in activityType.ActionTypes )
                    {
                        workflowActionType.SaveAttributeValues( rockContext );
                    }
                }

            } );

            var qryParams = new Dictionary<string, string>();
            qryParams["workflowTypeId"] = workflowType.Id.ToString();
            NavigateToPage( RockPage.Guid, qryParams );
        }
        /// <summary>
        /// Handles the Click event of the btnSave control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
        protected void btnSave_Click( object sender, EventArgs e )
        {
            ParseControls( true );

            var rockContext = new RockContext();
            var service = new WorkflowTypeService( rockContext );

            WorkflowType workflowType = null;

            int? workflowTypeId = hfWorkflowTypeId.Value.AsIntegerOrNull();
            if ( workflowTypeId.HasValue )
            {
                workflowType = service.Get( workflowTypeId.Value );
            }

            if ( workflowType == null )
            {
                workflowType = new WorkflowType();
            }

            workflowType.IsActive = cbIsActive.Checked;
            workflowType.Name = tbName.Text;
            workflowType.Description = tbDescription.Text;
            workflowType.CategoryId = cpCategory.SelectedValueAsInt();
            workflowType.Order = 0;
            workflowType.WorkTerm = tbWorkTerm.Text;
            workflowType.ProcessingIntervalSeconds = tbProcessingInterval.Text.AsIntegerOrNull();
            workflowType.IsPersisted = cbIsPersisted.Checked;
            workflowType.LoggingLevel = ddlLoggingLevel.SelectedValueAsEnum<WorkflowLoggingLevel>();
            workflowType.IconCssClass = tbIconCssClass.Text;

            if ( !Page.IsValid || !workflowType.IsValid )
            {
                return;
            }

            foreach(var activityType in ActivityTypesState)
            {
                if (!activityType.IsValid)
                {
                    return;
                }
                foreach(var actionType in activityType.ActionTypes)
                {
                    if ( !actionType.IsValid )
                    {
                        return;
                    }
                }
            }

            rockContext.WrapTransaction( () =>
            {
                // Save the entity field changes to workflow type
                if ( workflowType.Id.Equals( 0 ) )
                {
                    service.Add( workflowType );
                }
                rockContext.SaveChanges();

                // Save the workflow type attributes
                SaveAttributes( new Workflow().TypeId, "WorkflowTypeId", workflowType.Id.ToString(), AttributesState, rockContext );

                WorkflowActivityTypeService workflowActivityTypeService = new WorkflowActivityTypeService( rockContext );
                WorkflowActionTypeService workflowActionTypeService = new WorkflowActionTypeService( rockContext );
                WorkflowActionFormService workflowFormService = new WorkflowActionFormService( rockContext );
                WorkflowActionFormAttributeService workflowFormAttributeService = new WorkflowActionFormAttributeService( rockContext );

                // delete WorkflowActionTypes that aren't assigned in the UI anymore
                List<WorkflowActionType> actionTypesInDB = workflowActionTypeService.Queryable().Where( a => a.ActivityType.WorkflowTypeId.Equals( workflowType.Id ) ).ToList();
                List<WorkflowActionType> actionTypesInUI = new List<WorkflowActionType>();

                foreach ( var workflowActivity in ActivityTypesState )
                {
                    foreach ( var workflowAction in workflowActivity.ActionTypes )
                    {
                        actionTypesInUI.Add( workflowAction );
                    }
                }

                var deletedActionTypes = from actionType in actionTypesInDB
                                         where !actionTypesInUI.Select( u => u.Guid ).Contains( actionType.Guid )
                                         select actionType;
                deletedActionTypes.ToList().ForEach( actionType =>
                {
                    if ( actionType.WorkflowForm != null )
                    {
                        workflowFormService.Delete( actionType.WorkflowForm );
                    }
                    workflowActionTypeService.Delete( actionType );
                } );
                rockContext.SaveChanges();

                // delete WorkflowActivityTypes that aren't assigned in the UI anymore
                List<WorkflowActivityType> activityTypesInDB = workflowActivityTypeService.Queryable().Where( a => a.WorkflowTypeId.Equals( workflowType.Id ) ).ToList();
                var deletedActivityTypes = from activityType in activityTypesInDB
                                           where !ActivityTypesState.Select( u => u.Guid ).Contains( activityType.Guid )
                                           select activityType;
                deletedActivityTypes.ToList().ForEach( activityType =>
                {
                    workflowActivityTypeService.Delete( activityType );
                } );
                rockContext.SaveChanges();

                // add or update WorkflowActivityTypes(and Actions) that are assigned in the UI
                int workflowActivityTypeOrder = 0;
                foreach ( var editorWorkflowActivityType in ActivityTypesState )
                {
                    // Add or Update the activity type
                    WorkflowActivityType workflowActivityType = workflowType.ActivityTypes.FirstOrDefault( a => a.Guid.Equals( editorWorkflowActivityType.Guid ) );
                    if ( workflowActivityType == null )
                    {
                        workflowActivityType = new WorkflowActivityType();
                        workflowActivityType.Guid = editorWorkflowActivityType.Guid;
                        workflowType.ActivityTypes.Add( workflowActivityType );
                    }
                    workflowActivityType.IsActive = editorWorkflowActivityType.IsActive;
                    workflowActivityType.Name = editorWorkflowActivityType.Name;
                    workflowActivityType.Description = editorWorkflowActivityType.Description;
                    workflowActivityType.IsActivatedWithWorkflow = editorWorkflowActivityType.IsActivatedWithWorkflow;
                    workflowActivityType.Order = workflowActivityTypeOrder++;

                    // Save Activity Type
                    rockContext.SaveChanges();

                    // Save ActivityType Attributes
                    if ( ActivityAttributesState.ContainsKey( workflowActivityType.Guid ) )
                    {
                        SaveAttributes( new WorkflowActivity().TypeId, "ActivityTypeId", workflowActivityType.Id.ToString(), ActivityAttributesState[workflowActivityType.Guid], rockContext );
                    }

                    int workflowActionTypeOrder = 0;
                    foreach ( var editorWorkflowActionType in editorWorkflowActivityType.ActionTypes )
                    {
                        WorkflowActionType workflowActionType = workflowActivityType.ActionTypes.FirstOrDefault( a => a.Guid.Equals( editorWorkflowActionType.Guid ) );
                        if ( workflowActionType == null )
                        {
                            // New action
                            workflowActionType = new WorkflowActionType();
                            workflowActionType.Guid = editorWorkflowActionType.Guid;
                            workflowActivityType.ActionTypes.Add( workflowActionType );
                        }
                        workflowActionType.CriteriaAttributeGuid = editorWorkflowActionType.CriteriaAttributeGuid;
                        workflowActionType.CriteriaComparisonType = editorWorkflowActionType.CriteriaComparisonType;
                        workflowActionType.CriteriaValue = editorWorkflowActionType.CriteriaValue;
                        workflowActionType.Name = editorWorkflowActionType.Name;
                        workflowActionType.EntityTypeId = editorWorkflowActionType.EntityTypeId;
                        workflowActionType.IsActionCompletedOnSuccess = editorWorkflowActionType.IsActionCompletedOnSuccess;
                        workflowActionType.IsActivityCompletedOnSuccess = editorWorkflowActionType.IsActivityCompletedOnSuccess;
                        workflowActionType.Attributes = editorWorkflowActionType.Attributes;
                        workflowActionType.AttributeValues = editorWorkflowActionType.AttributeValues;
                        workflowActionType.Order = workflowActionTypeOrder++;

                        if ( workflowActionType.WorkflowForm != null && editorWorkflowActionType.WorkflowForm == null )
                        {
                            // Form removed
                            workflowFormService.Delete( workflowActionType.WorkflowForm );
                            workflowActionType.WorkflowForm = null;
                        }

                        if ( editorWorkflowActionType.WorkflowForm != null )
                        {
                            if ( workflowActionType.WorkflowForm == null )
                            {
                                workflowActionType.WorkflowForm = new WorkflowActionForm();
                            }

                            workflowActionType.WorkflowForm.NotificationSystemEmailId = editorWorkflowActionType.WorkflowForm.NotificationSystemEmailId;
                            workflowActionType.WorkflowForm.IncludeActionsInNotification = editorWorkflowActionType.WorkflowForm.IncludeActionsInNotification;
                            workflowActionType.WorkflowForm.AllowNotes = editorWorkflowActionType.WorkflowForm.AllowNotes;
                            workflowActionType.WorkflowForm.Header = editorWorkflowActionType.WorkflowForm.Header;
                            workflowActionType.WorkflowForm.Footer = editorWorkflowActionType.WorkflowForm.Footer;
                            workflowActionType.WorkflowForm.Actions = editorWorkflowActionType.WorkflowForm.Actions;
                            workflowActionType.WorkflowForm.ActionAttributeGuid = editorWorkflowActionType.WorkflowForm.ActionAttributeGuid;

                            var editorGuids = editorWorkflowActionType.WorkflowForm.FormAttributes
                                .Select( a => a.Attribute.Guid )
                                .ToList();

                            foreach ( var formAttribute in workflowActionType.WorkflowForm.FormAttributes
                                .Where( a => !editorGuids.Contains( a.Attribute.Guid ) ).ToList() )
                            {
                                workflowFormAttributeService.Delete( formAttribute );
                            }

                            int attributeOrder = 0;
                            foreach ( var editorAttribute in editorWorkflowActionType.WorkflowForm.FormAttributes.OrderBy( a => a.Order ) )
                            {
                                int attributeId = AttributeCache.Read( editorAttribute.Attribute.Guid, rockContext ).Id;

                                var formAttribute = workflowActionType.WorkflowForm.FormAttributes
                                    .Where( a => a.AttributeId == attributeId )
                                    .FirstOrDefault();

                                if ( formAttribute == null )
                                {
                                    formAttribute = new WorkflowActionFormAttribute();
                                    formAttribute.Guid = editorAttribute.Guid;
                                    formAttribute.AttributeId = attributeId;
                                    workflowActionType.WorkflowForm.FormAttributes.Add( formAttribute );
                                }

                                formAttribute.Order = attributeOrder++;
                                formAttribute.IsVisible = editorAttribute.IsVisible;
                                formAttribute.IsReadOnly = editorAttribute.IsReadOnly;
                                formAttribute.IsRequired = editorAttribute.IsRequired;
                                formAttribute.HideLabel = editorAttribute.HideLabel;
                                formAttribute.PreHtml = editorAttribute.PreHtml;
                                formAttribute.PostHtml = editorAttribute.PostHtml;
                            }
                        }
                    }
                }

                rockContext.SaveChanges();

                foreach ( var activityType in workflowType.ActivityTypes )
                {
                    foreach ( var workflowActionType in activityType.ActionTypes )
                    {
                        workflowActionType.SaveAttributeValues( rockContext );
                    }
                }

            } );

            var qryParams = new Dictionary<string, string>();
            qryParams["workflowTypeId"] = workflowType.Id.ToString();
            NavigateToPage( RockPage.Guid, qryParams );
        }
예제 #10
0
        /// <summary>
        /// Updates the email status.
        /// </summary>
        /// <param name="actionGuid">The action unique identifier.</param>
        /// <param name="status">The status.</param>
        /// <param name="emailEventType">Type of the email event.</param>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="ProcessWorkflow">if set to <c>true</c> [process workflow].</param>
        public static void UpdateEmailStatus( Guid actionGuid, string status, string emailEventType, RockContext rockContext, bool ProcessWorkflow )
        {
            var action = new WorkflowActionService( rockContext ).Get( actionGuid );
            if ( action != null && action.Activity != null )
            {

                string attrKey = action.ActionType.Guid.ToString() + "_EmailStatus";

                action.Activity.LoadAttributes( rockContext );
                string currentStatus = action.Activity.GetAttributeValue( attrKey );

                // Sometimes Clicked events are reported before opens. If this is the case, do not update the status from clicked to opened.
                bool updateStatus = true;
                if ( status == OPENED_STATUS && currentStatus == CLICKED_STATUS )
                {
                    updateStatus = false;
                }

                if ( !string.IsNullOrWhiteSpace( emailEventType ) && ( emailEventType != status || !updateStatus ) )
                {
                    action.AddLogEntry( string.Format( "Email Event Type: {0}", emailEventType ), true );
                }

                if ( updateStatus )
                {
                    action.Activity.SetAttributeValue( attrKey, status );
                    action.Activity.SaveAttributeValues( rockContext );
                    action.AddLogEntry( string.Format( "Email Status Updated to '{0}'", status ), true );
                }

                Guid? activityGuid = null;
                switch( status )
                {
                    case OPENED_STATUS:
                        {
                            activityGuid = GetActionAttributeValue( action, "OnOpenActivity" ).AsGuid();
                            break;
                        }
                    case CLICKED_STATUS:
                        {
                            activityGuid = GetActionAttributeValue( action, "OnClickedActivity" ).AsGuid();
                            break;
                        }
                    case FAILED_STATUS:
                        {
                            activityGuid = GetActionAttributeValue( action, "OnFailedActivity" ).AsGuid();
                            break;
                        }
                }

                if ( activityGuid.HasValue )
                {
                    var workflow = action.Activity.Workflow;
                    var activityType = new WorkflowActivityTypeService( rockContext ).Queryable()
                        .Where( a => a.Guid.Equals( activityGuid.Value ) ).FirstOrDefault();
                    if ( workflow != null && activityType != null )
                    {
                        WorkflowActivity.Activate( activityType, workflow );
                        action.AddLogEntry( string.Format( "Activated new '{0}' activity", activityType.ToString() ) );

                        if ( ProcessWorkflow )
                        {
                            List<string> workflowErrors;
                            new WorkflowService( rockContext ).Process( workflow, out workflowErrors );
                        }
                    }
                }

            }
        }
예제 #11
0
        /// <summary>
        /// Executes the specified workflow.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="action">The action.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        public override bool Execute( RockContext rockContext, WorkflowAction action, Object entity, out List<string> errorMessages )
        {
            errorMessages = new List<string>();

            double hoursElapsed = HoursElapsed( action );
            string emailStatus = EmailStatus( action );

            if ( hoursElapsed <= 0 )
            {
                SendEmail( rockContext, action );
            }
            else
            {
                var timedOut = false;

                var activityTypeService = new WorkflowActivityTypeService( rockContext );

                WorkflowActivityType unopenedActivityType = null;
                int? unopenedTimeout = null;
                Guid? guid = GetAttributeValue( action, "UnopenedTimeoutActivity" ).AsGuidOrNull();
                if ( guid.HasValue )
                {
                    unopenedActivityType = activityTypeService.Queryable().Where( a => a.Guid.Equals( guid.Value ) ).FirstOrDefault();
                    unopenedTimeout = GetAttributeValue( action, "UnopenedTimeoutLength" ).AsIntegerOrNull();

                    if ( emailStatus != OPENED_STATUS &&
                        emailStatus != CLICKED_STATUS &&
                        unopenedActivityType != null &&
                        unopenedTimeout.HasValue &&
                        unopenedTimeout.Value < hoursElapsed )
                    {
                        action.AddLogEntry( "Unopened Timeout Occurred", true );
                        WorkflowActivity.Activate( unopenedActivityType, action.Activity.Workflow, rockContext );
                        timedOut = true;
                    }
                }

                WorkflowActivityType noActionActivityType = null;
                int? noActionTimeout = null;
                guid = GetAttributeValue( action, "NoActionTimeoutActivity" ).AsGuidOrNull();
                if ( guid.HasValue )
                {
                    noActionActivityType = activityTypeService.Queryable().Where( a => a.Guid.Equals( guid.Value ) ).FirstOrDefault();
                    noActionTimeout = GetAttributeValue( action, "NoActionTimeoutLength" ).AsIntegerOrNull();

                    if ( emailStatus != CLICKED_STATUS &&
                        noActionActivityType != null &&
                        noActionTimeout.HasValue &&
                        noActionTimeout.Value < hoursElapsed )
                    {
                        action.AddLogEntry( "No Action Timeout Occurred", true );
                        WorkflowActivity.Activate( noActionActivityType, action.Activity.Workflow, rockContext );
                        timedOut = true;
                    }
                }

                if ( timedOut )
                {
                    UpdateEmailStatus( action.Guid, TIMEOUT_STATUS, string.Empty, rockContext, false );
                    return true;
                }
            }

            return false;
        }
예제 #12
0
        /// <summary>
        /// Handles the Click event of the btnSave control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
        protected void btnSave_Click( object sender, EventArgs e )
        {
            WorkflowType workflowType;
            WorkflowTypeService service = new WorkflowTypeService();

            int workflowTypeId = int.Parse( hfWorkflowTypeId.Value );

            if ( workflowTypeId == 0 )
            {
                workflowType = new WorkflowType();
                workflowType.IsSystem = false;
                workflowType.Name = string.Empty;
            }
            else
            {
                workflowType = service.Get( workflowTypeId );
            }

            workflowType.Name = tbName.Text;
            workflowType.Description = tbDescription.Text;
            workflowType.CategoryId = cpCategory.SelectedValueAsInt();
            workflowType.Order = int.Parse( tbOrder.Text );
            workflowType.WorkTerm = tbWorkTerm.Text;
            if ( !string.IsNullOrWhiteSpace( tbProcessingInterval.Text ) )
            {
                workflowType.ProcessingIntervalSeconds = int.Parse( tbProcessingInterval.Text );
            }

            workflowType.IsPersisted = cbIsPersisted.Checked;
            workflowType.LoggingLevel = ddlLoggingLevel.SelectedValueAsEnum<WorkflowLoggingLevel>();
            workflowType.IsActive = cbIsActive.Checked;

            if ( !Page.IsValid )
            {
                return;
            }

            if ( !workflowType.IsValid )
            {
                // Controls will render the error messages                    
                return;
            }

            RockTransactionScope.WrapTransaction( () =>
            {
                List<WorkflowActivityTypeEditor> workflowActivityTypeEditorList = phActivities.Controls.OfType<WorkflowActivityTypeEditor>().ToList();

                // delete WorkflowActionTypes that aren't assigned in the UI anymore
                WorkflowActionTypeService workflowActionTypeService = new WorkflowActionTypeService();
                List<WorkflowActionType> actionTypesInDB = workflowActionTypeService.Queryable().Where( a => a.ActivityType.WorkflowTypeId.Equals( workflowType.Id ) ).ToList();
                List<WorkflowActionType> actionTypesInUI = new List<WorkflowActionType>();
                foreach ( WorkflowActivityTypeEditor workflowActivityTypeEditor in workflowActivityTypeEditorList )
                {
                    foreach ( WorkflowActionTypeEditor editor in workflowActivityTypeEditor.Controls.OfType<WorkflowActionTypeEditor>() )
                    {
                        actionTypesInUI.Add( editor.WorkflowActionType );
                    }
                }

                var deletedActionTypes = from actionType in actionTypesInDB
                                         where !actionTypesInUI.Select( u => u.Guid ).Contains( actionType.Guid )
                                         select actionType;

                deletedActionTypes.ToList().ForEach( actionType =>
                {
                    workflowActionTypeService.Delete( actionType, CurrentPersonId );
                    workflowActionTypeService.Save( actionType, CurrentPersonId );
                } );

                // delete WorkflowActivityTypes that aren't assigned in the UI anymore
                WorkflowActivityTypeService workflowActivityTypeService = new WorkflowActivityTypeService();
                List<WorkflowActivityType> activityTypesInDB = workflowActivityTypeService.Queryable().Where( a => a.WorkflowTypeId.Equals( workflowType.Id ) ).ToList();
                List<WorkflowActivityType> activityTypesInUI = workflowActivityTypeEditorList.Select( a => a.GetWorkflowActivityType() ).ToList();

                var deletedActivityTypes = from activityType in activityTypesInDB
                                           where !activityTypesInUI.Select( u => u.Guid ).Contains( activityType.Guid )
                                           select activityType;

                deletedActivityTypes.ToList().ForEach( activityType =>
                {
                    workflowActivityTypeService.Delete( activityType, CurrentPersonId );
                    workflowActivityTypeService.Save( activityType, CurrentPersonId );
                } );

                // add or update WorkflowActivityTypes(and Actions) that are assigned in the UI
                int workflowActivityTypeOrder = 0;
                foreach ( WorkflowActivityTypeEditor workflowActivityTypeEditor in workflowActivityTypeEditorList )
                {
                    WorkflowActivityType editorWorkflowActivityType = workflowActivityTypeEditor.GetWorkflowActivityType();
                    WorkflowActivityType workflowActivityType = workflowType.ActivityTypes.FirstOrDefault( a => a.Guid.Equals( editorWorkflowActivityType.Guid ) );

                    if ( workflowActivityType == null )
                    {
                        workflowActivityType = editorWorkflowActivityType;
                        workflowType.ActivityTypes.Add( workflowActivityType );
                    }
                    else
                    {
                        workflowActivityType.Name = editorWorkflowActivityType.Name;
                        workflowActivityType.Description = editorWorkflowActivityType.Description;
                        workflowActivityType.IsActive = editorWorkflowActivityType.IsActive;
                        workflowActivityType.IsActivatedWithWorkflow = editorWorkflowActivityType.IsActivatedWithWorkflow;
                    }

                    workflowActivityType.Order = workflowActivityTypeOrder++;

                    int workflowActionTypeOrder = 0;
                    foreach ( WorkflowActionTypeEditor workflowActionTypeEditor in workflowActivityTypeEditor.Controls.OfType<WorkflowActionTypeEditor>() )
                    {
                        WorkflowActionType editorWorkflowActionType = workflowActionTypeEditor.WorkflowActionType;
                        WorkflowActionType workflowActionType = workflowActivityType.ActionTypes.FirstOrDefault( a => a.Guid.Equals( editorWorkflowActionType.Guid ) );
                        if ( workflowActionType == null )
                        {
                            workflowActionType = editorWorkflowActionType;
                            workflowActivityType.ActionTypes.Add( workflowActionType );
                        }
                        else
                        {
                            workflowActionType.Name = editorWorkflowActionType.Name;
                            workflowActionType.EntityTypeId = editorWorkflowActionType.EntityTypeId;
                            workflowActionType.IsActionCompletedOnSuccess = editorWorkflowActionType.IsActionCompletedOnSuccess;
                            workflowActionType.IsActivityCompletedOnSuccess = editorWorkflowActionType.IsActivityCompletedOnSuccess;
                            workflowActionType.Attributes = editorWorkflowActionType.Attributes;
                            workflowActionType.AttributeValues = editorWorkflowActionType.AttributeValues;
                        }
                        

                        workflowActionType.Order = workflowActionTypeOrder++;
                    }
                }

                if ( workflowType.Id.Equals( 0 ) )
                {
                    service.Add( workflowType, CurrentPersonId );
                }

                service.Save( workflowType, CurrentPersonId );

                foreach ( var activityType in workflowType.ActivityTypes )
                {
                    foreach ( var workflowActionType in activityType.ActionTypes )
                    {
                        Rock.Attribute.Helper.SaveAttributeValues( workflowActionType, CurrentPersonId );
                    }
                }

                
            } );
            
            var qryParams = new Dictionary<string, string>();
            qryParams["workflowTypeId"] = workflowType.Id.ToString();
            NavigateToPage( RockPage.Guid, qryParams );
        }