示例#1
0
        public override async Task <CompletionResult> Complete(string data, Guid?activityResultID)
        {
            //default to SaveResultID if resultID not specified
            if (!activityResultID.HasValue)
            {
                activityResultID = SaveResultID;
            }

            await db.Entry(_entity).ReloadAsync();

            var task = PmnTask.GetActiveTaskForRequestActivity(_entity.ID, ID, db);

            if (activityResultID.Value == SubmitResultID) //Submit
            {
                await db.LoadCollection(_entity, (r) => r.DataMarts);

                var filters = new ExtendedQuery
                {
                    Projects             = (a) => a.ProjectID == _entity.ProjectID,
                    ProjectOrganizations = a => a.ProjectID == _entity.ProjectID && a.OrganizationID == _entity.OrganizationID,
                    Organizations        = a => a.OrganizationID == _entity.OrganizationID,
                    Users = a => a.UserID == _entity.CreatedByID
                };

                var permissions = await db.HasGrantedPermissions <Request>(_workflow.Identity, _entity, filters, PermissionIdentifiers.Request.SkipSubmissionApproval);

                await db.Entry(_entity).ReloadAsync();

                if (Newtonsoft.Json.JsonConvert.DeserializeObject <Lpp.Dns.DTO.QueryComposer.QueryComposerRequestDTO>(_entity.Query).Where.Criteria.Any(c => c.Terms.Any(t => t.Type.ToString().ToUpper() == "2F60504D-9B2F-4DB1-A961-6390117D3CAC") || c.Criteria.Any(ic => ic.Terms.Any(t => t.Type.ToString().ToUpper() == "2F60504D-9B2F-4DB1-A961-6390117D3CAC"))))
                {
                    if (!permissions.Contains(PermissionIdentifiers.Request.SkipSubmissionApproval))
                    {
                        //file distribution never requires review before submission, add the permission if the user does not have it.
                        permissions = new[] { PermissionIdentifiers.Request.SkipSubmissionApproval };
                    }

                    await db.LoadCollection(_entity, (r) => r.DataMarts);

                    if (!_entity.DataMarts.Any())
                    {
                        throw new Exception("At least one routing needs to be specified when submitting a requests.");
                    }

                    //prepare the request documents, save created documents same as legacy
                    IList <Guid> documentRevisionSets = Newtonsoft.Json.JsonConvert.DeserializeObject <IList <Guid> >(data);

                    IEnumerable <Document> documents = await(from d in db.Documents.AsNoTracking()
                                                             join x in (
                                                                 db.Documents.Where(dd => documentRevisionSets.Contains(dd.RevisionSetID.Value))
                                                                 .GroupBy(k => k.RevisionSetID)
                                                                 .Select(k => k.OrderByDescending(d => d.MajorVersion).ThenByDescending(d => d.MinorVersion).ThenByDescending(d => d.BuildVersion).ThenByDescending(d => d.RevisionVersion).Select(y => y.ID).Distinct().FirstOrDefault())
                                                                 ) on d.ID equals x
                                                             orderby d.ItemID descending, d.RevisionSetID descending, d.CreatedOn descending
                                                             select d).ToArrayAsync();

                    await db.Entry(_entity).Reference(r => r.Activity).LoadAsync();

                    await db.Entry(_entity).Reference(r => r.RequestType).LoadAsync();

                    string submitterEmail = await db.Users.Where(u => u.ID == _workflow.Identity.ID).Select(u => u.Email).SingleAsync();

                    //update the request
                    _entity.SubmittedByID         = _workflow.Identity.ID;
                    _entity.SubmittedOn           = DateTime.UtcNow;
                    _entity.AdapterPackageVersion = System.Diagnostics.FileVersionInfo.GetVersionInfo(this.GetType().Assembly.Location).FileVersion;
                    _entity.RejectedByID          = null;
                    _entity.RejectedOn            = null;
                    _entity.Private = false;


                    //save the changes to the request now since the trigger for routings will change the status invalidating the object before save
                    await db.SaveChangesAsync();

                    await db.Entry(_entity).ReloadAsync();

                    var originalStatus = _entity.Status;
                    await SetRequestStatus(DTO.Enums.RequestStatuses.Submitted, false);

                    var allTasks = await db.ActionReferences.Where(tr => tr.ItemID == _entity.ID &&
                                                                   tr.Type == DTO.Enums.TaskItemTypes.Request &&
                                                                   tr.Task.Type == DTO.Enums.TaskTypes.Task
                                                                   )
                                   .Select(tr => tr.Task.ID).ToArrayAsync();

                    var attachments = await(from doc in db.Documents.AsNoTracking()
                                            join x in (
                                                db.Documents.Where(dd => allTasks.Contains(dd.ItemID))
                                                .GroupBy(k => k.RevisionSetID)
                                                .Select(k => k.OrderByDescending(d => d.MajorVersion).ThenByDescending(d => d.MinorVersion).ThenByDescending(d => d.BuildVersion).ThenByDescending(d => d.RevisionVersion).Select(y => y.ID).Distinct().FirstOrDefault())
                                                ) on doc.ID equals x
                                            where allTasks.Contains(doc.ItemID) && doc.Kind == "Attachment.Input"
                                            orderby doc.ItemID descending, doc.RevisionSetID descending, doc.CreatedOn descending
                                            select doc).ToArrayAsync();

                    foreach (var dm in _entity.DataMarts.Where(dm => dm.Status == 0 || dm.Status == DTO.Enums.RoutingStatus.AwaitingRequestApproval || dm.Status == DTO.Enums.RoutingStatus.Draft))
                    {
                        dm.Status = DTO.Enums.RoutingStatus.Submitted;

                        var currentResponse = db.Responses.Include(rsp => rsp.RequestDocument).FirstOrDefault(r => r.RequestDataMartID == dm.ID && r.Count == r.RequestDataMart.Responses.Max(rr => rr.Count));
                        if (currentResponse == null)
                        {
                            currentResponse = db.Responses.Add(new Response {
                                RequestDataMartID = dm.ID
                            });
                        }
                        currentResponse.SubmittedByID = _workflow.Identity.ID;
                        currentResponse.SubmittedOn   = DateTime.UtcNow;

                        //add the request document associations
                        for (int i = 0; i < documentRevisionSets.Count; i++)
                        {
                            if (!currentResponse.RequestDocument.Any(rd => rd.RevisionSetID == documentRevisionSets[i]))
                            {
                                db.RequestDocuments.Add(new RequestDocument {
                                    RevisionSetID = documentRevisionSets[i], ResponseID = currentResponse.ID, DocumentType = DTO.Enums.RequestDocumentType.Input
                                });
                            }
                        }

                        foreach (var attachment in attachments)
                        {
                            if (!currentResponse.RequestDocument.Any(rd => rd.RevisionSetID == attachment.RevisionSetID.Value))
                            {
                                db.RequestDocuments.Add(new RequestDocument {
                                    RevisionSetID = attachment.RevisionSetID.Value, ResponseID = currentResponse.ID, DocumentType = DTO.Enums.RequestDocumentType.AttachmentInput
                                });
                            }
                        }
                    }

                    await db.SaveChangesAsync();

                    //reload the request since altering the routings triggers a change of the request status in the db by a trigger.
                    await db.Entry(_entity).ReloadAsync();

                    DTO.QueryComposer.QueryComposerRequestDTO qcRequestDTO = Newtonsoft.Json.JsonConvert.DeserializeObject <DTO.QueryComposer.QueryComposerRequestDTO>(_entity.Query);
                    var fileUploadTerm = qcRequestDTO.Where.Criteria.SelectMany(c => c.Terms.Where(t => t.Type == FileUploadTermID)).FirstOrDefault();
                    var termValues     = Newtonsoft.Json.JsonConvert.DeserializeObject <FileUploadValues>(fileUploadTerm.Values["Values"].ToString());

                    //update the request.json term value to include system generated documents revisionsetIDs
                    termValues.Documents.Clear();

                    for (int i = 0; i < documentRevisionSets.Count; i++)
                    {
                        termValues.Documents.Add(new FileUploadValues.Document {
                            RevisionSetID = documentRevisionSets[i]
                        });
                    }

                    fileUploadTerm.Values["Values"] = termValues;
                    _entity.Query = Newtonsoft.Json.JsonConvert.SerializeObject(qcRequestDTO);

                    await db.SaveChangesAsync();

                    await NotifyRequestStatusChanged(originalStatus, DTO.Enums.RequestStatuses.Submitted);
                }
                else
                {
                    await db.LoadCollection(_entity, (r) => r.DataMarts);

                    var parentDocument = db.Documents.FirstOrDefault(d => d.ItemID == _entity.ID && d.Kind == DocumentKind && d.ParentDocumentID == null);

                    byte[] documentContent = System.Text.UTF8Encoding.UTF8.GetBytes(_entity.Query ?? string.Empty);
                    var    document        = new Document
                    {
                        Name             = "Request Criteria",
                        MajorVersion     = parentDocument == null ? 1 : parentDocument.MajorVersion,
                        MinorVersion     = parentDocument == null ? 0 : parentDocument.MinorVersion,
                        RevisionVersion  = parentDocument == null ? 0 : parentDocument.RevisionVersion,
                        MimeType         = "application/json",
                        Viewable         = false,
                        UploadedByID     = _workflow.Identity.ID,
                        FileName         = "request.json",
                        CreatedOn        = DateTime.UtcNow,
                        BuildVersion     = parentDocument == null ? 0 : parentDocument.BuildVersion,
                        ParentDocumentID = parentDocument == null ? (Guid?)null : parentDocument.ID,
                        ItemID           = task.ID,
                        Length           = documentContent.LongLength,
                        Kind             = Dns.DTO.Enums.DocumentKind.Request
                    };

                    db.Documents.Add(document);
                    document.RevisionSetID = document.ID;
                    await db.SaveChangesAsync();

                    document.SetData(db, documentContent);


                    _entity.AdapterPackageVersion = System.Diagnostics.FileVersionInfo.GetVersionInfo(this.GetType().Assembly.Location).FileVersion;
                    //Reset reject for resubmit.
                    _entity.RejectedByID = null;
                    _entity.RejectedOn   = null;
                    _entity.Private      = false;

                    await db.SaveChangesAsync();

                    DTO.Enums.RequestStatuses newRequestStatus = DTO.Enums.RequestStatuses.AwaitingRequestApproval;

                    if (permissions.Contains(PermissionIdentifiers.Request.SkipSubmissionApproval))
                    {
                        _entity.SubmittedByID = _workflow.Identity.ID;
                        _entity.SubmittedOn   = DateTime.UtcNow;

                        await db.SaveChangesAsync();

                        var allTasks = await db.ActionReferences.Where(tr => tr.ItemID == _entity.ID &&
                                                                       tr.Type == DTO.Enums.TaskItemTypes.Request &&
                                                                       tr.Task.Type == DTO.Enums.TaskTypes.Task
                                                                       )
                                       .Select(tr => tr.Task.ID).ToArrayAsync();

                        var attachments = await(from doc in db.Documents.AsNoTracking()
                                                join x in (
                                                    db.Documents.Where(dd => allTasks.Contains(dd.ItemID))
                                                    .GroupBy(k => k.RevisionSetID)
                                                    .Select(k => k.OrderByDescending(d => d.MajorVersion).ThenByDescending(d => d.MinorVersion).ThenByDescending(d => d.BuildVersion).ThenByDescending(d => d.RevisionVersion).Select(y => y.ID).Distinct().FirstOrDefault())
                                                    ) on doc.ID equals x
                                                where allTasks.Contains(doc.ItemID) && doc.Kind == "Attachment.Input"
                                                orderby doc.ItemID descending, doc.RevisionSetID descending, doc.CreatedOn descending
                                                select doc).ToArrayAsync();

                        _entity.Status = DTO.Enums.RequestStatuses.Submitted;
                        foreach (var dm in _entity.DataMarts)
                        {
                            dm.Status = DTO.Enums.RoutingStatus.Submitted;

                            var currentResponse = db.Responses.Include(rsp => rsp.RequestDocument).FirstOrDefault(r => r.RequestDataMartID == dm.ID && r.Count == r.RequestDataMart.Responses.Max(rr => rr.Count));
                            if (currentResponse == null)
                            {
                                currentResponse = db.Responses.Add(new Response {
                                    RequestDataMartID = dm.ID
                                });
                            }
                            currentResponse.SubmittedByID = _workflow.Identity.ID;
                            currentResponse.SubmittedOn   = DateTime.UtcNow;

                            if (!currentResponse.RequestDocument.Any(rd => rd.RevisionSetID == document.RevisionSetID.Value))
                            {
                                db.RequestDocuments.Add(new RequestDocument {
                                    RevisionSetID = document.RevisionSetID.Value, ResponseID = currentResponse.ID, DocumentType = DTO.Enums.RequestDocumentType.Input
                                });
                            }

                            foreach (var attachment in attachments)
                            {
                                if (!currentResponse.RequestDocument.Any(rd => rd.RevisionSetID == attachment.RevisionSetID.Value))
                                {
                                    db.RequestDocuments.Add(new RequestDocument {
                                        RevisionSetID = attachment.RevisionSetID.Value, ResponseID = currentResponse.ID, DocumentType = DTO.Enums.RequestDocumentType.AttachmentInput
                                    });
                                }
                            }
                        }
                    }
                    else
                    {
                        _entity.Status = DTO.Enums.RequestStatuses.AwaitingRequestApproval;
                        foreach (var dm in _entity.DataMarts)
                        {
                            dm.Status = DTO.Enums.RoutingStatus.AwaitingRequestApproval;
                        }
                    }

                    await db.SaveChangesAsync();

                    await db.Entry(_entity).ReloadAsync();
                    await SetRequestStatus(newRequestStatus);


                    await MarkTaskComplete(task);
                }

                return(new CompletionResult
                {
                    ResultID = permissions.Contains(PermissionIdentifiers.Request.SkipSubmissionApproval) ? SubmitResultID : ReviewResultID
                });
            }
            else if (activityResultID.Value == SaveResultID) //Save
            {
                if (_entity.Private)
                {
                    await db.Entry(_entity).ReloadAsync();

                    _entity.Private = false;

                    await task.LogAsModifiedAsync(_workflow.Identity, db);

                    await db.SaveChangesAsync();
                }

                return(new CompletionResult
                {
                    ResultID = SaveResultID
                });
            }
            else if (activityResultID.Value == DeleteResultID) //Delete
            {
                _workflow.DataContext.Requests.Remove(_workflow.Entity);

                if (task != null)
                {
                    db.Actions.Remove(task);
                }

                await _workflow.DataContext.SaveChangesAsync();

                return(null);
            }
            else
            {
                throw new ArgumentOutOfRangeException(CommonMessages.ActivityResultNotSupported);
            }
        }
        public override async Task <ValidationResult> Validate(Guid?activityResultID)
        {
            if (activityResultID == null)
            {
                return(new ValidationResult
                {
                    Success = false,
                    Errors = CommonMessages.ActivityResultIDRequired
                });
            }

            var permissions = await db.GetGrantedWorkflowActivityPermissionsForRequestAsync(_workflow.Identity, _entity);

            if (!permissions.Contains(PermissionIdentifiers.ProjectRequestTypeWorkflowActivities.EditTask) && (activityResultID.Value == SaveResultID || activityResultID.Value == ModifyResultID))
            {
                return(new ValidationResult
                {
                    Success = false,
                    Errors = CommonMessages.RequirePermissionToEditTask
                });
            }

            if (!permissions.Contains(PermissionIdentifiers.ProjectRequestTypeWorkflowActivities.CloseTask) && (activityResultID.Value == SubmitResultID))
            {
                return(new ValidationResult
                {
                    Success = false,
                    Errors = CommonMessages.RequirePermissionToCloseTask
                });
            }

            if (!permissions.Contains(PermissionIdentifiers.ProjectRequestTypeWorkflowActivities.CloseTask) && (activityResultID.Value == TerminateResultID))
            {
                return(new ValidationResult
                {
                    Success = false,
                    Errors = CommonMessages.RequirePermissionToTerminateWorkflow
                });
            }

            var errors = new StringBuilder();

            if (activityResultID.Value == SubmitResultID)
            {
                if (_entity.ProjectID == null)
                {
                    errors.AppendHtmlLine("Please ensure that you have selected a project for the request.");
                }

                if (_entity.DueDate.HasValue && _entity.DueDate.Value < DateTime.UtcNow)
                {
                    errors.AppendHtmlLine("The Request Due Date must be set in the future.");
                }

                var dataMartsDueDate = false;
                foreach (var dm in _entity.DataMarts)
                {
                    if (dm.DueDate.HasValue && dm.DueDate.Value.Date < DateTime.UtcNow.Date)
                    {
                        dataMartsDueDate = true;
                    }
                }
                if (dataMartsDueDate)
                {
                    errors.AppendHtmlLine("The Request's DataMart Due Dates must be set in the future.");
                }

                if (_entity.SubmittedOn.HasValue)
                {
                    errors.AppendHtmlLine("Cannot submit a request that has already been submitted");
                }

                if (_entity.Template)
                {
                    errors.AppendHtmlLine("Cannot submit a request template");
                }

                if (_entity.Scheduled)
                {
                    errors.AppendHtmlLine("Cannot submit a scheduled request");
                }

                await db.LoadReference(_entity, (r) => r.Project);

                //If a project loaded successfully check it.
                if (_entity.Project != null)
                {
                    if (!_entity.Project.Active || _entity.Project.Deleted)
                    {
                        errors.AppendHtmlLine("Cannot submit a request for an inactive or deleted project.");
                    }

                    if (_entity.Project.EndDate < DateTime.UtcNow)
                    {
                        errors.AppendHtmlLine("Cannot submit a request for a project that has ended.");
                    }

                    await db.LoadCollection(_entity.Project, (p) => p.DataMarts);

                    if (_entity.DataMarts.Any(dm => !_entity.Project.DataMarts.Any(pdm => pdm.DataMartID == dm.DataMartID)))
                    {
                        errors.AppendHtmlLine("The request contains datamarts that are not part of the project specified and thus cannot be processed. Please remove these datamarts and try again.");
                    }
                }

                await db.LoadCollection(_entity, (r) => r.DataMarts);

                var dataMarts = _entity.GetGrantedDataMarts(db, _workflow.Identity);

                if (_entity.DataMarts.Any(dm => !dataMarts.Any(gdm => gdm.ID == dm.DataMartID)))
                {
                    errors.AppendHtmlLine("This request contains datamarts you are not permitted to submit to. Please remove them and try again.");
                }


                var filters = new ExtendedQuery
                {
                    Projects             = (a) => a.ProjectID == _entity.ProjectID,
                    ProjectOrganizations = a => a.ProjectID == _entity.ProjectID && a.OrganizationID == _entity.OrganizationID,
                    Organizations        = a => a.OrganizationID == _entity.OrganizationID,
                    Users = a => a.UserID == _entity.CreatedByID
                };

                if (_entity.DataMarts.Count < 2)
                {
                    var skip2DataMartRulePerms = await db.HasGrantedPermissions <Request>(_workflow.Identity, _entity, filters, PermissionIdentifiers.Portal.SkipTwoDataMartRule);

                    if (!skip2DataMartRulePerms.Contains(PermissionIdentifiers.Portal.SkipTwoDataMartRule))
                    {
                        errors.AppendHtmlLine("Cannot submit a request with less than 2 datamarts");
                    }
                }
            }


            if (errors.Length > 0)
            {
                return(new ValidationResult
                {
                    Success = false,
                    Errors = errors.ToString()
                });
            }
            else
            {
                return(new ValidationResult
                {
                    Success = true
                });
            }
        }
示例#3
0
        public override async Task <CompletionResult> Complete(string data, Guid?activityResultID)
        {
            if (!activityResultID.HasValue)
            {
                throw new ArgumentNullException(CommonMessages.ActivityResultIDRequired);
            }


            if (activityResultID.Value == SaveResultID)
            {
                return(new CompletionResult {
                    ResultID = SaveResultID
                });
            }
            else if (activityResultID.Value == RejectResultID)
            {
                _entity.Status = DTO.Enums.RequestStatuses.RequestRejected;

                var task = PmnTask.GetActiveTaskForRequestActivity(_entity.ID, ID, db);

                var originalStatus = _entity.Status;
                await SetRequestStatus(DTO.Enums.RequestStatuses.RequestRejected);
                await NotifyRequestStatusChanged(originalStatus, DTO.Enums.RequestStatuses.RequestRejected);

                await MarkTaskComplete(task);

                await db.SaveChangesAsync();

                return(new CompletionResult
                {
                    ResultID = RejectResultID
                });
            }
            else if (activityResultID.Value == ApproveResultID)
            {
                var filters = new ExtendedQuery
                {
                    Projects             = (a) => a.ProjectID == _entity.ProjectID,
                    ProjectOrganizations = a => a.ProjectID == _entity.ProjectID && a.OrganizationID == _entity.OrganizationID,
                    Organizations        = a => a.OrganizationID == _entity.OrganizationID,
                    Users = a => a.UserID == _entity.CreatedByID
                };

                var permissions = await db.HasGrantedPermissions <Request>(_workflow.Identity, _entity, filters, PermissionIdentifiers.Request.ApproveRejectSubmission);

                if (!permissions.Contains(PermissionIdentifiers.Request.ApproveRejectSubmission))
                {
                    throw new SecurityException(CommonMessages.RequirePermissionToApproveOrRejectRequestSubmission);
                }

                var originalStatus = _entity.Status;
                await SetRequestStatus(DTO.Enums.RequestStatuses.RequestPendingDistribution);

                await db.LoadCollection(_entity, (r) => r.DataMarts);

                await NotifyRequestStatusChanged(originalStatus, DTO.Enums.RequestStatuses.RequestPendingDistribution);

                var task = PmnTask.GetActiveTaskForRequestActivity(_entity.ID, ID, db);
                await MarkTaskComplete(task);

                return(new CompletionResult
                {
                    ResultID = ApproveResultID
                });
            }
            else
            {
                throw new NotSupportedException(CommonMessages.ActivityResultNotSupported);
            }
        }
示例#4
0
        /// <summary>
        /// Performs common submit validation of a request.
        /// </summary>
        /// <returns>Any error messages, empty if valid.</returns>
        protected async Task <string> PerformSubmitValidation()
        {
            var errors = new StringBuilder();

            if (_entity.ProjectID == null)
            {
                errors.AppendHtmlLine("Please ensure that you have selected a project for the request.");
            }

            if (_entity.DueDate.HasValue && _entity.DueDate.Value < DateTime.UtcNow)
            {
                errors.AppendHtmlLine("The Request Due Date must be set in the future.");
            }

            var dataMartsDueDate = false;

            foreach (var dm in _entity.DataMarts)
            {
                if (dm.DueDate.HasValue && dm.DueDate.Value.Date < DateTime.UtcNow.Date)
                {
                    dataMartsDueDate = true;
                }
            }
            if (dataMartsDueDate)
            {
                errors.AppendHtmlLine("The Request's DataMart Due Dates must be set in the future.");
            }

            if (_entity.SubmittedOn.HasValue && _entity.Status != Lpp.Dns.DTO.Enums.RequestStatuses.RequestRejected) //Rejected requests can be re-submitted.
            {
                errors.AppendHtmlLine("Cannot submit a request that has already been submitted");
            }

            if (_entity.Template)
            {
                errors.AppendHtmlLine("Cannot submit a request template");
            }

            if (_entity.Scheduled)
            {
                errors.AppendHtmlLine("Cannot submit a scheduled request");
            }

            await db.LoadReference(_entity, (r) => r.Project);

            await db.LoadCollection(_entity, (r) => r.DataMarts);

            //If a project loaded successfully check it.
            if (_entity.Project != null)
            {
                if (!_entity.Project.Active || _entity.Project.Deleted)
                {
                    errors.AppendHtmlLine("Cannot submit a request for an inactive or deleted project.");
                }

                if (_entity.Project.EndDate < DateTime.UtcNow)
                {
                    errors.AppendHtmlLine("Cannot submit a request for a project that has ended.");
                }

                await db.LoadCollection(_entity.Project, (p) => p.DataMarts);

                if (_entity.DataMarts.Any(dm => !_entity.Project.DataMarts.Any(pdm => pdm.DataMartID == dm.DataMartID)))
                {
                    errors.AppendHtmlLine("The request contains datamarts that are not part of the project specified and thus cannot be processed. Please remove these datamarts and try again.");
                }
            }


            var dataMarts = await GetAllAvailableDataMarts();

            if (_entity.DataMarts.Any(dm => !dataMarts.Any(gdm => gdm == dm.DataMartID)))
            {
                errors.AppendHtmlLine("This request contains datamarts you are not permitted to submit to. Please remove them and try again.");
            }


            var filters = new ExtendedQuery
            {
                Projects             = (a) => a.ProjectID == _entity.ProjectID,
                ProjectOrganizations = a => a.ProjectID == _entity.ProjectID && a.OrganizationID == _entity.OrganizationID,
                Organizations        = a => a.OrganizationID == _entity.OrganizationID,
                Users = a => a.UserID == _entity.CreatedByID
            };

            if (_entity.DataMarts.Count < 2)
            {
                var skip2DataMartRulePerms = await db.HasGrantedPermissions <Request>(_workflow.Identity, _entity, filters, PermissionIdentifiers.Portal.SkipTwoDataMartRule);

                if (!skip2DataMartRulePerms.Contains(PermissionIdentifiers.Portal.SkipTwoDataMartRule))
                {
                    errors.AppendHtmlLine("Cannot submit a request with less than 2 datamarts");
                }
            }

            return(errors.ToString());
        }
        private bool SubmitRequest(Guid requestID, ApiIdentity identity)
        {
            /**
             * Due to concurrency issues that are being created somehow by doing the update first
             * this operation is being done using a standalone datacontext and fresh data from db.
             * */
            RoutingStatus targetStatus = RoutingStatus.AwaitingRequestApproval;

            using (var datacontext = new DataContext())
            {
                var request = datacontext.Requests.Include(r => r.DataMarts.Select(rr => rr.Responses)).Include(r => r.RequestType).Single(r => r.ID == requestID);
                var project = datacontext.Projects.SingleOrDefault(p => p.ID == request.ProjectID);

                if (project == null)
                {
                    /**
                     * BMS: We used to allow a metadata request to be submitted w/o a project, however this causes the request to be lost from any view,
                     * so now I force the request to a project until we figure out how to display requests w/o project assignments.
                     **/
                    throw new Exception("Cannot submit a request outside of a Project context. Please select a Project.");
                }

                if (!project.Active || project.Deleted)
                {
                    throw new Exception("Cannot submit requests for project " + project.Name + ", because the project is marked inactive.");
                }

                if (project.StartDate != null && project.StartDate > DateTime.UtcNow)
                {
                    throw new Exception("Cannot submit requests for project " + project.Name + ", because the project has not started yet.");
                }

                if (project.EndDate != null && project.EndDate < DateTime.UtcNow)
                {
                    throw new Exception("Cannot submit requests for project " + project.Name + ", because the project has already finished.");
                }

                var dueDate = request.DueDate;
                if (dueDate != null && dueDate < DateTime.UtcNow.Date)
                {
                    throw new Exception("Due date must be set in the future.");
                }

                var pastDueDate = false;
                foreach (var dm in request.DataMarts)
                {
                    if (dm.DueDate != null && dm.DueDate < DateTime.UtcNow.Date)
                    {
                        pastDueDate = true;
                    }
                }
                if (pastDueDate)
                {
                    throw new Exception("Request's DataMart Due dates must be set in the future.");
                }

                var grantedDataMarts      = GetGrantedDataMarts(project, request.RequestTypeID, identity).ToArray();
                var nonGrantedDataMartIDs = datacontext.RequestDataMarts.Where(dm => dm.RequestID == request.ID).Select(dm => dm.DataMartID).Except(grantedDataMarts.Select(d => d.ID)).ToArray();
                if (nonGrantedDataMartIDs.Length > 0)
                {
                    var nonGrantedDmNames = datacontext.DataMarts.Where(dm => nonGrantedDataMartIDs.Contains(dm.ID)).Select(dm => dm.Name);
                    throw new Exception("You do not have permission to submit requests of type '" + request.RequestType.Name + "' to the following data marts: " + string.Join(", ", nonGrantedDmNames));
                }

                // Remove datamarts that do not belong to the Project
                var invalidDataMarts = (from dm in datacontext.RequestDataMarts.Where(d => d.RequestID == request.ID)
                                        join pdm in datacontext.ProjectDataMarts.Where(p => p.ProjectID == request.ProjectID) on dm.DataMartID equals pdm.DataMartID into pdms
                                        where !pdms.Any()
                                        select dm).ToList();
                if (invalidDataMarts.Count > 0)
                {
                    datacontext.RequestDataMarts.RemoveRange(invalidDataMarts);
                }

                if (request.SubmittedOn.HasValue)
                {
                    throw new Exception("Cannot submit a request that has already been submitted");
                }

                if (request.Template)
                {
                    throw new Exception("Cannot submit a request template");
                }

                if (request.Scheduled)
                {
                    throw new Exception("Cannot submit a scheduled request");
                }

                var filters = new ExtendedQuery
                {
                    Projects             = (a) => a.ProjectID == request.ProjectID,
                    ProjectOrganizations = a => a.ProjectID == request.ProjectID && a.OrganizationID == request.OrganizationID,
                    Organizations        = a => a.OrganizationID == request.OrganizationID,
                    Users = a => a.UserID == request.CreatedByID
                };

                if (request.DataMarts.Count < 2)
                {
                    var skip2DataMartRulePerms = AsyncHelpers.RunSync(() => datacontext.HasGrantedPermissions <Request>(identity, request, filters, PermissionIdentifiers.Portal.SkipTwoDataMartRule));

                    if (!skip2DataMartRulePerms.Contains(PermissionIdentifiers.Portal.SkipTwoDataMartRule))
                    {
                        throw new Exception("Cannot submit a request with less than 2 datamarts.");
                    }
                }

                var permissions = AsyncHelpers.RunSync(() => datacontext.HasGrantedPermissions <Request>(identity, request, filters, PermissionIdentifiers.Request.SkipSubmissionApproval));

                if (permissions.Contains(PermissionIdentifiers.Request.SkipSubmissionApproval))
                {
                    targetStatus = RoutingStatus.Submitted;
                }
                request.Status        = targetStatus == RoutingStatus.Submitted ? RequestStatuses.Submitted : RequestStatuses.AwaitingRequestApproval;
                request.SubmittedOn   = DateTime.UtcNow;
                request.SubmittedByID = identity.ID;

                //set the version on the request
                request.AdapterPackageVersion = System.Diagnostics.FileVersionInfo.GetVersionInfo(this.GetType().Assembly.Location).FileVersion;

                foreach (var d in request.DataMarts)
                {
                    if (grantedDataMarts.Any(dm => dm.ID == d.DataMartID))
                    {
                        d.Status = targetStatus;
                        foreach (var response in d.Responses)
                        {
                            response.SubmittedByID = identity.ID;
                            response.SubmittedOn   = request.SubmittedOn ?? DateTime.UtcNow;
                        }
                    }
                    else
                    {
                        datacontext.RequestDataMarts.Remove(d);
                    }
                }
                datacontext.SaveChanges();

                //SALMAN - TODO
                //if (result.IsSuccess && targetStatus == RoutingStatus.Submitted)
                //{
                //    ExecuteIfLocalRequest(ctx, datacontext);
                //}
                //return result;

                return(true);
            }
        }
        public async Task <HttpResponseMessage> Register(CNDSRegisterRequestDTO dto)
        {
            await ConfirmProxyUser(dto);

            var requestTypeDetails = await DataContext.RequestTypes.Where(rt => rt.ID == dto.RequestTypeID)
                                     .Select(rt => new
            {
                rt.ID,
                rt.WorkflowID,
                StartActivityID     = rt.Workflow.RequestReviewWorkflowActivityID ?? DataContext.WorkflowActivityCompletionMaps.Where(wa => wa.WorkflowID == rt.WorkflowID && wa.SourceWorkflowActivity.Start == true).Select(wa => wa.SourceWorkflowActivityID).FirstOrDefault(),
                SubmittedActivityID = rt.Workflow.CompleteDistributionWorkflowActivityID,
                WorkflowRoleID      = rt.Workflow.Roles.Where(wr => wr.IsRequestCreator == true).Select(wr => wr.ID).FirstOrDefault()
            }
                                             ).FirstOrDefaultAsync();

            DTO.RequestDTO sourceRequest = Newtonsoft.Json.JsonConvert.DeserializeObject <DTO.RequestDTO>(dto.RequestDetails);

            //register the request, routes, responses, documents
            var request = DataContext.Requests.Add(new Data.Request
            {
                ID                 = dto.ParticipantID,
                ProjectID          = dto.ProjectID,
                RequestTypeID      = dto.RequestTypeID,
                WorkflowID         = requestTypeDetails.WorkflowID,
                WorkFlowActivityID = requestTypeDetails.StartActivityID,
                CreatedByID        = dto.SourceNetworkID,
                UpdatedByID        = dto.SourceNetworkID,
                SubmittedOn        = DateTime.UtcNow,
                SubmittedByID      = dto.SourceNetworkID,
                Description        = sourceRequest.Description,
                //TODO: figure out the naming format of the request
                Name                  = sourceRequest.Project + ": " + sourceRequest.Name,
                OrganizationID        = Requests.RequestsController.CNDSOrganizationRouteProxyID,
                Priority              = sourceRequest.Priority,
                Query                 = sourceRequest.Query,
                DataMarts             = new List <RequestDataMart>(),
                AdapterPackageVersion = System.Diagnostics.FileVersionInfo.GetVersionInfo(this.GetType().Assembly.Location).FileVersion,
                RejectedByID          = null,
                RejectedOn            = null,
                Private               = false
            });

            if (sourceRequest.DueDate.HasValue)
            {
                request.DueDate = sourceRequest.DueDate.Value.DateTime;
            }

            request.Users.Add(new RequestUser
            {
                RequestID      = request.ID,
                UserID         = dto.SourceNetworkID,
                WorkflowRoleID = requestTypeDetails.WorkflowRoleID
            });

            var workflowTask = DataContext.Actions.Add(PmnTask.CreateForWorkflowActivity(request.ID, request.WorkFlowActivityID.Value, request.WorkflowID.Value, DataContext));

            //register the documents
            List <Document> documents = new List <Document>();

            foreach (var doc in dto.Documents)
            {
                var document = DataContext.Documents.Add(new Document
                {
                    ID            = doc.DocumentID,
                    RevisionSetID = doc.RevisionSetID,
                    ItemID        = workflowTask.ID,
                    Name          = doc.Name,
                    FileName      = doc.FileName,
                    Kind          = doc.Kind,
                    Length        = doc.Length,
                    Description   = doc.Description,
                    MimeType      = doc.MimeType,
                    UploadedByID  = dto.SourceNetworkID
                });

                DataContext.ActionReferences.Add(new TaskReference {
                    TaskID = workflowTask.ID, ItemID = document.ID, Type = DTO.Enums.TaskItemTypes.ActivityDataDocument
                });
                documents.Add(document);
            }

            foreach (var datamart in dto.Routes)
            {
                var route = new RequestDataMart
                {
                    ID          = datamart.RouteID,
                    DataMartID  = datamart.DataMartID,
                    DueDate     = datamart.DueDate,
                    Priority    = datamart.Priority,
                    RequestID   = request.ID,
                    RoutingType = DTO.Enums.RoutingType.ExternalCNDS,
                    //default status is awaiting request approval, if the proxy user has permission to skip will be updated and notification sent to source request
                    Status    = DTO.Enums.RoutingStatus.AwaitingRequestApproval,
                    Responses = new HashSet <Response>()
                };

                var response = route.AddResponse(request.CreatedByID);
                response.ID = datamart.ResponseID;

                var responseDocuments = datamart.DocumentIDs.Select(docID => {
                    var dd = documents.First(d => d.ID == docID);
                    return(new RequestDocument {
                        DocumentType = DTO.Enums.RequestDocumentType.Input, ResponseID = response.ID, RevisionSetID = dd.RevisionSetID.Value
                    });
                });

                DataContext.RequestDocuments.AddRange(responseDocuments);

                request.DataMarts.Add(DataContext.RequestDataMarts.Add(route));
            }

            //Parse the query and fix the document references in the fileupload and modular program terms
            DTO.QueryComposer.QueryComposerRequestDTO queryDTO = Newtonsoft.Json.JsonConvert.DeserializeObject <DTO.QueryComposer.QueryComposerRequestDTO>(request.Query);
            var fileUploadTerms = queryDTO.Where.Criteria.SelectMany(c => c.Terms.Where(t => t.Type == Lpp.QueryComposer.ModelTermsFactory.FileUploadID || t.Type == QueryComposer.ModelTermsFactory.ModularProgramID)).ToArray();

            if (fileUploadTerms.Length > 0)
            {
                foreach (var term in fileUploadTerms)
                {
                    var termValue = Newtonsoft.Json.JsonConvert.DeserializeObject <FileUploadValues>(term.Values["Values"].ToString());
                    foreach (var termDoc in termValue.Documents)
                    {
                        var docDTO = dto.Documents.Where(d => d.SourceRevisionSetID == termDoc.RevisionSetID).FirstOrDefault();
                        if (docDTO != null)
                        {
                            termDoc.RevisionSetID = docDTO.RevisionSetID;
                        }
                    }

                    term.Values["Values"] = termValue;
                }

                request.Query = Newtonsoft.Json.JsonConvert.SerializeObject(queryDTO);
            }

            try
            {
                await DataContext.SaveChangesAsync();
            }
            catch (Exception ex)
            {
                Logger.Error("Error saving request: " + request.ID, ex);
                System.Diagnostics.Debugger.Break();
                return(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex));
            }

            if (documents.Count > 0)
            {
                //var tasks = dto.Documents.Select(async doc => await GetDocumentContent(doc.DocumentID));
                //await Task.WhenAll(tasks);

                foreach (var doc in documents)
                {
                    await GetDocumentContent(doc.ID);
                }
            }

            //Submit the request if the proxy user has permission to skip request approval
            var permissionFilter = new ExtendedQuery
            {
                Projects             = (a) => a.ProjectID == request.ProjectID,
                ProjectOrganizations = (a) => a.ProjectID == request.ProjectID && a.OrganizationID == request.OrganizationID,
                Organizations        = (a) => a.OrganizationID == request.OrganizationID,
                Users = (a) => a.UserID == request.CreatedByID
            };

            var apiIdentity = new Utilities.Security.ApiIdentity(dto.SourceNetworkID, dto.SourceNetworkName.Replace(" ", "_"), dto.SourceNetworkName, Requests.RequestsController.CNDSOrganizationRouteProxyID);
            var permissions = await DataContext.HasGrantedPermissions <Request>(apiIdentity, request.ID, permissionFilter, Dns.DTO.Security.PermissionIdentifiers.Request.SkipSubmissionApproval);

            if (permissions.Contains(DTO.Security.PermissionIdentifiers.Request.SkipSubmissionApproval))
            {
                await DataContext.Entry(request).ReloadAsync();

                await DataContext.Entry(request).Collection(r => r.DataMarts).LoadAsync();

                var responses = (await DataContext.RequestDataMarts.Where(rdm => rdm.RequestID == request.ID && rdm.Status == DTO.Enums.RoutingStatus.AwaitingRequestApproval).SelectMany(rdm => rdm.Responses.Where(rsp => rsp.Count == rdm.Responses.Max(rr => rr.Count))).ToArrayAsync()).ToDictionary(r => r.RequestDataMartID);

                //update the routings to Submitted
                foreach (var dm in request.DataMarts)
                {
                    await DataContext.Entry(dm).ReloadAsync();

                    Response response = null;
                    if (responses.TryGetValue(dm.ID, out response))
                    {
                        response.SubmittedByID = dto.SourceNetworkID;
                        response.SubmittedOn   = DateTime.UtcNow;
                    }

                    dm.Status = DTO.Enums.RoutingStatus.Submitted;
                }
                try
                {
                    await DataContext.SaveChangesAsync();
                }
                catch (Exception ex) {
                    Logger.Error(ex.Message, ex);
                    return(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex));
                }

                //update the request to submitted
                //manually override the request status using sql direct, EF does not allow update of computed
                await DataContext.Database.ExecuteSqlCommandAsync("UPDATE Requests SET Status = @status WHERE ID = @ID", new System.Data.SqlClient.SqlParameter("@status", (int)DTO.Enums.RequestStatuses.Submitted), new System.Data.SqlClient.SqlParameter("@ID", request.ID));

                await DataContext.Entry(request).ReloadAsync();

                //close the review task
                workflowTask.Status          = DTO.Enums.TaskStatuses.Complete;
                workflowTask.EndOn           = DateTime.UtcNow;
                workflowTask.PercentComplete = 100d;

                //create a new task for the next activity, and set the activity on the request
                request.WorkFlowActivityID = requestTypeDetails.SubmittedActivityID;
                var submitTask = DataContext.Actions.Add(PmnTask.CreateForWorkflowActivity(request.ID, request.WorkFlowActivityID.Value, request.WorkflowID.Value, DataContext));
                try
                {
                    await DataContext.SaveChangesAsync();
                }
                catch (Exception ex)
                {
                    Logger.Error(ex.Message, ex);
                    return(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex));
                }

                //notify CNDS of request status change, which will in turn notify the source network to update the status of the route
                System.Web.Hosting.HostingEnvironment.QueueBackgroundWorkItem(async cancellationToken =>
                {
                    using (var helper = new Lpp.CNDS.ApiClient.NetworkRequestDispatcher())
                    {
                        foreach (var responseID in dto.Routes.Select(rt => rt.ResponseID))
                        {
                            await helper.UpdateSourceRoutingStatus(new[] { new DTO.CNDSUpdateRoutingStatusDTO {
                                                                               ResponseID = responseID, Message = string.Empty, RoutingStatus = DTO.Enums.RoutingStatus.Submitted
                                                                           } });
                        }
                    }
                });
            }


            return(Request.CreateResponse(HttpStatusCode.OK));;
        }