/// <summary>
 /// Creates a PDF document of <paramref name="product"/> and saves it to <paramref name="path"/>.
 /// </summary>
 /// <param name="writer">The writer that acts as the this instance.</param>
 /// <param name="product">The product to create a PDF for.</param>
 /// <param name="controlsAccess">The control access list.</param>
 /// <param name="path">A relative or absolute path for the file that the document will be saved to.</param>
 public static void WritePdfToFilesystem(this IProductPdfWriter writer, ProductDefinition product, List<ControlAccess> controlsAccess, string path)
 {
     using (FileStream stream = new FileStream(path, FileMode.CreateNew, FileAccess.Write))
     {
         writer.WritePdfToStream(product, controlsAccess, stream);
     }
 }
        public void TestProductSave()
        {
            if (!this.connected)
            {
                Assert.Inconclusive("Could not connect to database instance '{0}'", this.client.GetServer().Instance.Address);
            }

            MongoCollection<BsonDocument> collection = this.database.GetCollection(iApplyDb.Metadata._COLLECTION_NAME);

            ProductDefinition product = new ProductDefinition
            {
                OrganisationId = OrganisationId,
                Version = 1,
                WorkflowState = ProductWorkflowState.Current,
                BranchName = "Working Copy"
            };

            Assert.IsNull(product.Id);
            product = this.dataAccess.SaveProduct(product);
            Assert.IsNotNull(product.Id);
            product.ClearInternalId();

            IMongoQuery metadataQry = Query.And(Query.EQ(iApplyDb.Metadata.PRODUCT_ID, new BsonString(product.Id)));

            Assert.AreEqual(1, product.Version);
            Assert.AreEqual(1, collection.Count(metadataQry));

            product.Version = 2;
            product = this.dataAccess.SaveProduct(product);

            Assert.AreEqual(2, product.Version);
            Assert.AreEqual(2, collection.Count(metadataQry));
        }
        public void ValidateMissingDataSourceConfiguration()
        {
            const string id = "3b3cf1a7631f4c3c9d58714549ec6d4d";
            const string name = "Missing Security Configuration";
            ProductDefinition product = new ProductDefinition { Id = id, Name = name };
            MigrationData migrationData = new MigrationData();
            migrationData.Products.Add(product);
            migrationData.WorkflowConfigurations.Add(new WorkflowConfigurationContainer { ExternalId = id, Configuration = new WorkflowConfiguration() });
            migrationData.SystemVersion = new Version(16, 5);
            migrationData.Security = new List<SecurityConfiguration>() { new SecurityConfiguration(new ApplicationEntitlementList() { new ApplicationEntitlement(id, AccessLevel.NoAccess) { ProductId = id } }) };

            MigrationDataResults results = this.validator.Validate(migrationData);

            MigrationDataMessageList messages = results.GetNotificationsFor(product);
            Assert.AreEqual(1, messages.Count());
            MigrationDataMessage message = messages.First();
            Assert.AreEqual(MessageType.Error, message.MessageType);
            Assert.AreEqual(string.Format("Missing Data Source configuration for Product \"{0}\" - Product will not be imported", name), message.Message);
        }
        public void WriteProductPdfWithEveryControl()
        {
            ControlList list = ControlListActivator.CreateControlList();
            var entitlements = new List<ControlAccess>();
            entitlements.AddRange(list.Select(c => new ControlAccess(c.Id, AccessLevel.Write)));

            ProductPdfWriter writer = new ProductPdfWriter();
            ProductDefinition product = new ProductDefinition
                                            {
                                                FormDefinition = new FormDefinition { Pages = new PageList() }
                                            };
            Page page = new UserPage();
            product.FormDefinition.Pages.Add(page);
            page.Controls = list;

            using (MemoryStream stream = new MemoryStream())
            {
                writer.WritePdfToStream(product, entitlements, stream);
            }
        }
        /// <summary>
        /// Creates the document to be saved.
        /// </summary>
        /// <param name="product">The product to create a PDF for.</param>
        /// <param name="controlsAccess">The control access list.</param>
        private void CreateDocument(ProductDefinition product, List<ControlAccess> controlsAccess)
        {
            this.document = this.CreateDocument(product.Name);

            ControlListRenderer listRenderer = new ControlListRenderer(this.document, controlsAccess);
            ControlRendererFactory rendererFactory = new ControlRendererFactory(this.document, listRenderer);

            this.document.Styles.AddStyle(PdfResources.StyleNameMandatory, StyleNames.Normal);
            this.document.Styles[PdfResources.StyleNameMandatory].Font.Color = Colors.Red;

            foreach (var page in product.FormDefinition.Pages.Where(p => p.PageType == PageType.UserDefined))
            {
                if (product.FormDefinition.Pages.Count > 1)
                {
                    this.document.LastSection.AddParagraph(page.PageTitle, StyleNames.Heading1);
                }

                listRenderer.Render(page.Controls, rendererFactory, 0, product.FormDefinition.Pages.AllControls);
            }
        }
        /// <summary>
        /// Disseminates the changes to <paramref name="targetProduct"/>.
        /// </summary>
        /// <param name="targetProduct">The child form to which changes will be disseminated.</param>
        /// <param name="targetVariations">Control variations that exclude controls from dissemination.</param>
        public void Disseminate(ProductDefinition targetProduct, ProductVariation targetVariations)
        {
            foreach (PageDelta editedPageDelta in this.delta.EditedPages)
            {
                Page childPage = targetProduct.FormDefinition.Pages.FindByPageId(editedPageDelta.Revision.PageId);

                foreach (Control removed in editedPageDelta.RemovedControls)
                {
                    if (!targetVariations.UnlinkedControls.Contains(removed.Id))
                    {
                        childPage.Controls.RecursiveRemove(removed.Id);
                    }
                }

                foreach (Control control in editedPageDelta.SortedUpsertedControls)
                {
                    if (editedPageDelta.AddedControls.IndexOf(control) != -1)
                    {
                        int nextId = targetProduct.FormDefinition.Pages.GetNextControlId();
                        this.AddControl(control, childPage, targetVariations, nextId);
                    }
                    else if (editedPageDelta.EditedControls.IndexOf(control) != -1)
                    {
                        this.EditControl(control, childPage, targetVariations);
                    }
                }
            }

            int position = 1;
            foreach (Page p in targetProduct.FormDefinition.Pages)
            {
                foreach (Control c in p.Controls.Flatten())
                {
                    c.Position = position++;
                }
            }
        }
 public void LocalTestInitialize()
 {
     string json = AssemblyResourceReader.ReadAsString(string.Format("Test_Data.Metadata.FORM-{0}.json", FORM_ID));
     this.product = JsonConvert.DeserializeObject<ProductDefinition>(json);
     var container = new UnityContainer().LoadConfiguration();
     this.entitlementProvider = container.Resolve<IApplicationEntitlementProvider>();
 }
 public void LocalTestInitialize()
 {
     string json = AssemblyResourceReader.ReadAsString(string.Format("Test_Data.Metadata.FORM-{0}.json", FORM_ID));
     this.product = JsonConvert.DeserializeObject<ProductDefinition>(json);
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="ProductDelta"/> class.
 /// </summary>
 /// <param name="original">The original product.</param>
 /// <param name="revision">The revised product.</param>
 public ProductDelta(ProductDefinition original, ProductDefinition revision)
 {
     this.Original = original;
     this.Revision = revision;
     this.DetermineDelta();
 }
        /// <summary>
        /// Updates the service endpoints.
        /// </summary>
        /// <param name="product">The product.</param>
        /// <param name="productDataSourceConfiguration">The product data source configuration.</param>
        /// <param name="workflowConfiguration">The workflow configuration.</param>
        /// <param name="serviceEndpointMap">The service endpoint map.</param>
        private void UpdateServiceEndpoints(ProductDefinition product, ProductDataSourceConfiguration productDataSourceConfiguration, WorkflowConfiguration workflowConfiguration, Dictionary<string, string> serviceEndpointMap)
        {
            string mappedId;
            bool available;

            // Search controls
            List<SearchControl> searchControls = product.FormDefinition.Pages.AllControls.FindAllRecursive<SearchControl>(x => x.Type == ControlType.Search);
            foreach (SearchControl searchControl in searchControls)
            {
                available = serviceEndpointMap.TryGetValue(searchControl.SearchSource.ServiceEndpointId, out mappedId);
                if (available)
                {
                    searchControl.SearchSource.ServiceEndpointId = mappedId;
                }
            }

            // Dynamic Option controls
            List<ControlWithOptions> dynamicOptionControls = product.FormDefinition.Pages.AllControls.FindAllRecursive<ControlWithOptions>(x => x.OptionSource.Type == OptionSourceType.Dynamic);
            foreach (ControlWithOptions dynamicOptionControl in dynamicOptionControls)
            {
                available = serviceEndpointMap.TryGetValue(((DynamicOptionSource)dynamicOptionControl.OptionSource).ServiceEndpointId, out mappedId);
                if (available)
                {
                    ((DynamicOptionSource)dynamicOptionControl.OptionSource).ServiceEndpointId = mappedId;
                }
            }

            // External Validation handlers
            ServiceEndpointUtilisationList externalRuleHandlers = product.FormDefinition.Pages.AllExternalRuleHandlers;
            foreach (ServiceEndpointUtilisation externalRuleHandler in externalRuleHandlers)
            {
                available = serviceEndpointMap.TryGetValue(externalRuleHandler.ServiceEndpointId, out mappedId);
                if (available)
                {
                    externalRuleHandler.ServiceEndpointId = mappedId;
                }
            }

            // Product Data sources
            foreach (ProductDataSource productDataSource in productDataSourceConfiguration.DataSources)
            {
                available = serviceEndpointMap.TryGetValue(productDataSource.ServiceEndpointId, out mappedId);
                if (available)
                {
                    productDataSource.ServiceEndpointId = mappedId;
                }
            }

            // Webhook events
            IEnumerable<IWorkflowTransitionAction> webhookEvents = workflowConfiguration.States.SelectMany(x => x.GetAllEvents(WorkflowTransitionActionType.Webhook)).Where(x => x is WebhookWorkflowTransitionAction);
            foreach (WebhookWorkflowTransitionAction webhookEvent in webhookEvents)
            {
                available = serviceEndpointMap.TryGetValue(webhookEvent.ServiceEndpointId, out mappedId);
                if (available)
                {
                    webhookEvent.ServiceEndpointId = mappedId;
                }
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="RetrieveApplicationResponse" /> class.
 /// </summary>
 /// <param name="application">The application.</param>
 /// <param name="product">The product.</param>
 public RetrieveApplicationResponse(Application application, ProductDefinition product)
 {
     this.Application = application;
     this.Product = product;
 }
        /// <summary>
        /// Validates an application.
        /// </summary>
        /// <param name="application">The application to validate.</param>
        /// <param name="pagesToValidate">The pagesToValidate to validate.</param>
        /// <param name="controls">A list of all controls.</param>
        /// <param name="controlsAccess">The control access list for the current user.</param>
        /// <param name="subpageControlId">The id of the control acting as the current subpage. If <see langword="null" />, then all controls are validated.</param>
        /// <param name="product">The product object.</param>
        /// <returns>
        /// The <see cref="ValidationResults" />.
        /// </returns>
        private ValidationResults ValidateApplication(Application application, PageList pagesToValidate, ControlList controls, List<ControlAccess> controlsAccess, int? subpageControlId = null, ProductDefinition product = null)
        {
            List<ControlWithOptions> controlsWithOptions = controls.FindAllRecursive<ControlWithOptions>();

            if (controlsWithOptions.Any())
            {
                this.RegisterOptionControls(application.FormOrganisationId, true, controlsWithOptions, application.ApplicationData);
            }

            var controlList = pagesToValidate.AllControls;
            var ruleList = pagesToValidate.AllRules;

            if (subpageControlId != null)
            {
                var subpageControl = controlList.FindRecursive<GroupControl>(x => x.Id == subpageControlId);
                if (subpageControl != null)
                {
                    controlList = new ControlList { subpageControl };

                    TruthConditionList validRules = new TruthConditionList();
                    validRules.AddRange(ruleList.Where(rule => controlList.FindRecursive(x => x.Id.ToString().Equals(((ValidateTruthCondition)rule).Error.Position)) != null));

                    ruleList = validRules;
                }
            }

            ServiceEndpointList endpointList = pagesToValidate.AllExternalRuleHandlers.Count > 0 ?
                     this.DataAccess.GetServiceEndpointList() :
                     new ServiceEndpointList();

            RegexValidatorList regexValidators = this.DataAccess.GetValidatorList();

            if (product != null)
            {
                this.FillControlReferences(pagesToValidate, product.FormDefinition.Pages.AllControls);
                foreach (var referencedControls in pagesToValidate.Select(p => p.ReferencedControls))
                {
                    foreach (var control in referencedControls)
                    {
                        var exists = controls.FindRecursive(control.Name) != null;
                        if (exists)
                        {
                            continue;
                        }

                        controls.AddRange(referencedControls);
                    }
                }
            }

            ApplicationValidator validator = new ApplicationValidator(controls, controlList, controlsAccess, ruleList, pagesToValidate.AllExternalRuleHandlers, endpointList, this.endpointCommunicator, regexValidators);
            return validator.Validate(application);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="ProductDisseminator"/> class.
 /// </summary>
 /// <param name="original">The previous version of the parent form.</param>
 /// <param name="revision">The new version of the parent form that contains the changes to be disseminated.</param>
 public ProductDisseminator(ProductDefinition original, ProductDefinition revision)
 {
     this.delta = new ProductDelta(original, revision);
 }
 /// <summary>
 /// Creates a PDF document of <paramref name="product" /> and sends it to <paramref name="target" />.
 /// </summary>
 /// <param name="product">The product to create a PDF for.</param>
 /// <param name="controlsAccess">The control access list.</param>
 /// <param name="target">The target stream.</param>
 public void WritePdfToStream(ProductDefinition product, List<ControlAccess> controlsAccess, Stream target)
 {
     this.CreateDocument(product, controlsAccess);
     this.WritePdf(this.document, target);
 }
        /// <summary>
        /// Gets a list of pages that the user is entitled to view.
        /// </summary>
        /// <param name="sessionData">The session data.</param>
        /// <param name="product">The product.</param>
        /// <param name="applicationId">State of the application.</param>
        /// <returns>
        /// A list of pages that the user is entitled to view.
        /// </returns>
        public PageList GetAuthorisedPages(SessionData sessionData, ProductDefinition product, string applicationId)
        {
            User user = this.userManager.GetUserById(sessionData.UserId);
            SecureSession secureSession = new SecureSession(sessionData.DeserializationSource, sessionData.SessionId, user);
            RoleList roles = this.DataAccess.GetRoleList();

            Application app = string.IsNullOrWhiteSpace(applicationId) ? this.CreateApplicationSecure(sessionData, product.Id, false, product.Version).Application : this.GetApplication(applicationId);

            PageList allPages = product.FormDefinition.Pages;
            ControlList allControls = allPages.AllControls;

            List<PageAccess> pagesAccess = this.entitlementProvider.GetPagesAccess(secureSession, app, allPages, roles, product.Version);

            PageList accessiblePages = new PageList();
            bool receiptPageExists = pagesAccess.Any(p => p.Id == 999);
            foreach (var page in allPages)
            {
                if (!receiptPageExists && page.PageType == PageType.Receipt)
                {
                    accessiblePages.Add(page);
                }

                var entitlement = pagesAccess.FirstOrDefault(e => e.Id == page.PageId);
                if (entitlement != null)
                {
                    if (entitlement.AccessLevel >= AccessLevel.Read)
                    {
                        accessiblePages.Add(page);
                    }
                }
            }

            List<ControlAccess> controlsAccess = this.entitlementProvider.GetControlsAccess(secureSession, app, accessiblePages.AllControls, roles, product.Version);

            this.RemoveInaccessibleControls(accessiblePages, controlsAccess);
            this.FillControlReferences(accessiblePages, allControls);

            return accessiblePages;
        }
            private void GetTestObjects(string id, out ProductDisseminator disseminator, out ProductDefinition child, out ProductVariation variation)
            {
                string jsonString = AssemblyResourceReader.ReadAsString(string.Format("Test_Data.Disseminator.{0}-Parent-Original.json", id));
                ProductDefinition original = JsonConvert.DeserializeObject<ProductDefinition>(jsonString);

                jsonString = AssemblyResourceReader.ReadAsString(string.Format("Test_Data.Disseminator.{0}-Parent-Revision.json", id));
                ProductDefinition revision = JsonConvert.DeserializeObject<ProductDefinition>(jsonString);

                jsonString = AssemblyResourceReader.ReadAsString(string.Format("Test_Data.Disseminator.{0}-Child.json", id));
                child = JsonConvert.DeserializeObject<ProductDefinition>(jsonString);

                jsonString = AssemblyResourceReader.ReadAsString(string.Format("Test_Data.Disseminator.{0}-Child-Variation.json", id));
                variation = JsonConvert.DeserializeObject<ProductVariation>(jsonString);

                disseminator = new ProductDisseminator(original, revision);
            }
        /// <summary>
        /// Performs workflow on behalf of the submit.
        /// </summary>
        /// <param name="secureSession">The session data.</param>
        /// <param name="application">The application to perform workflow for.</param>
        /// <param name="existingApplicationData">The existing application data.</param>
        /// <param name="product">The product definition.</param>
        /// <param name="scopedPageList">The list of pages required to process the application in its current state.</param>
        /// <param name="currentItemState">The current workflow state.</param>
        /// <param name="workflowState">The new / requested workflow state.</param>
        /// <param name="assignee">The assignee value from the workflow transition.</param>
        /// <param name="assigneeType">The assignee type from the workflow transition.</param>
        /// <param name="newState">After a successful transition, will be the new workflow state, otherwise <see langword="null"/>.</param>
        /// <returns>After a successful transition, the workflow item, otherwise <see langword="null"/>.</returns>
        private ApplicationWorkflowItem PerformWorkflow(SecureSession secureSession, Application application, ApplicationData existingApplicationData, ProductDefinition product, PageList scopedPageList, ItemState currentItemState, string workflowState, string assignee, ComparisonType? assigneeType, out ItemState newState)
        {
            newState = currentItemState;

            WorkflowConfigurationContainer workflowContainer = this.workflowService.GetWorkflowConfiguration(WorkflowTargetType.FormApplication, application.FormId, product.Version);
            WorkflowState state = workflowContainer.Configuration.States.FirstOrDefault(s => s.Name == currentItemState.Name);

            WorkflowTransition transition = (state == null) ?
                                                       null :
                                                            string.IsNullOrWhiteSpace(workflowState) ?
                                                            null :
                                                                state.Transitions.FirstOrDefault(t => t.Trigger != TriggerEvent.Submit && t.ExitStateName == workflowState);

            Organisation entitleTo;

            ApplicationWorkflowItem workflowItem = new ApplicationWorkflowItem(application, existingApplicationData, scopedPageList.AllControls)
            {
                FormVersion = product.Version
            };

            // Do non-submit transition. Only Service accounts can perform this operation.
            if (transition != null && secureSession.AuthenticatedUser != null && secureSession.AuthenticatedUser.AccountType == AccountType.Service)
            {
                User assignTo = this.DetermineAssignee(assignee, assigneeType, application);
                application.WorkflowState = transition.ExitStateName;
                application.StateTransitionDate = DateTime.Now;
                application.AssignedTo = (assignTo != null) ? assignTo.Id : null;
                application.AssignedToDisplayName = (assignTo != null) ? assignTo.DisplayName : null;

                entitleTo = this.DetermineOrganisation(transition.ExitOrganisation, application);
                application.OrganisationId = (entitleTo != null) ? entitleTo.Id : application.OrganisationId;
                application.OrganisationName = (entitleTo != null) ? entitleTo.Name : application.OrganisationName;

                return workflowItem;
            }

            // Do submit transition.
            WorkflowResult result = this.workflowService.Trigger(workflowItem, new WorkflowTransition { Trigger = TriggerEvent.Submit }, currentItemState);

            // If result = null, there were NO valid transitions, so we leave the application essentially as is, but unassign it.
            if (result == null)
            {
                application.AssignedTo = null;
                application.AssignedToDisplayName = null;
            }

            if (result != null)
            {
                newState = result.ExitState;
                if (newState != null && string.Compare(newState.Name, application.WorkflowState, StringComparison.OrdinalIgnoreCase) != 0)
                {
                    application.StateTransitionDate = DateTime.Now;
                }

                application.WorkflowState = (newState == null) ? null : newState.Name;

                User user = this.DetermineAssignee(result.ExitAssignee, result.ExitAssigneeType, application);
                application.AssignedTo = (user != null) ? user.Id : null;
                application.AssignedToDisplayName = (user != null) ? user.DisplayName : null;

                entitleTo = this.DetermineOrganisation(result.ExitOrganisation, application);
                application.OrganisationId = (entitleTo != null) ? entitleTo.Id : application.OrganisationId;
                application.OrganisationName = (entitleTo != null) ? entitleTo.Name : application.OrganisationName;
            }

            return workflowItem;
        }