示例#1
0
        /// <summary>
        /// Performs tasks associated to the start of the activity. By default confirms that an active PmnTask has been created for the current activity, and also records any comment entered when leaving the previous activity.
        /// </summary>
        /// <param name="comment"></param>
        /// <returns></returns>
        public virtual async Task Start(string comment)
        {
            var task = await PmnTask.GetActiveTaskForRequestActivityAsync(_entity.ID, ID, db);

            if (task == null)
            {
                task = db.Actions.Add(PmnTask.CreateForWorkflowActivity(_entity.ID, ID, _workflow.ID, db, CustomTaskSubject));
                await db.SaveChangesAsync();
            }

            if (!string.IsNullOrWhiteSpace(comment))
            {
                var cmt = db.Comments.Add(new Comment
                {
                    CreatedByID = _workflow.Identity.ID,
                    ItemID      = _entity.ID,
                    Text        = comment
                });

                db.CommentReferences.Add(new CommentReference
                {
                    CommentID = cmt.ID,
                    Type      = DTO.Enums.CommentItemTypes.Task,
                    ItemTitle = task.Subject,
                    ItemID    = task.ID
                });

                await db.SaveChangesAsync();
            }
        }
示例#2
0
        /// <summary>
        /// Marks the current activity's task as modified.
        /// </summary>
        /// <param name="optionalMessage"></param>
        /// <returns></returns>
        protected async Task LogTaskModified(string optionalMessage = null)
        {
            var task = await PmnTask.GetActiveTaskForRequestActivityAsync(_entity.ID, ID, db);

            if (task == null)
            {
                task = db.Actions.Add(PmnTask.CreateForWorkflowActivity(_entity.ID, ID, _workflow.ID, db));
                return;
            }

            await task.LogAsModifiedAsync(_workflow.Identity, db, optionalMessage);
        }
示例#3
0
        public async override Task <CompletionResult> Complete(string data, Guid?activityResultID)
        {
            if (activityResultID.Value == SaveResultID)
            {
                return(new CompletionResult
                {
                    ResultID = SaveResultID
                });
            }

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

            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();

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

            if (activityResultID.Value == ApproveResultID)
            {
                _entity.SubmittedByID = _workflow.Identity.ID;
                _entity.SubmittedOn   = DateTime.UtcNow;

                var responses = await db.RequestDataMarts.Where(rdm => rdm.RequestID == _entity.ID && rdm.Status == DTO.Enums.RoutingStatus.AwaitingRequestApproval).SelectMany(rdm => rdm.Responses.Where(rsp => rsp.Count == rdm.Responses.Max(rr => rr.Count))).ToArrayAsync();

                var previousTask = await(from a in db.Actions
                                         join ar in db.ActionReferences on a.ID equals ar.TaskID
                                         where ar.ItemID == _entity.ID && a.Status == DTO.Enums.TaskStatuses.Complete select a).OrderByDescending(p => p.CreatedOn).FirstOrDefaultAsync();

                var document = await(from d in db.Documents.AsNoTracking()
                                     join x in (
                                         db.Documents.Where(dd => dd.ItemID == previousTask.ID && dd.FileName == "request.json" && dd.Kind == Dns.DTO.Enums.DocumentKind.Request)
                                         .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).FirstOrDefaultAsync();

                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 == DTO.Enums.RoutingStatus.AwaitingRequestApproval))
                {
                    dm.Status = DTO.Enums.RoutingStatus.Submitted;

                    var currentResponse = responses.Where(rsp => rsp.RequestDataMartID == dm.ID).FirstOrDefault();
                    if (currentResponse == null)
                    {
                        currentResponse = db.Responses.Add(new Response {
                            RequestDataMartID = dm.ID
                        });
                    }
                    currentResponse.SubmittedByID = _workflow.Identity.ID;
                    currentResponse.SubmittedOn   = DateTime.UtcNow;

                    //get existing request documents associated to the response, add only missing documents
                    var existingRequestDocuments = await db.RequestDocuments.Where(rd => rd.ResponseID == currentResponse.ID).ToArrayAsync();

                    if (!existingRequestDocuments.Any(ed => ed.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.Where(att => !existingRequestDocuments.Any(ed => ed.RevisionSetID == att.RevisionSetID.Value)))
                    {
                        db.RequestDocuments.Add(new RequestDocument {
                            RevisionSetID = attachment.RevisionSetID.Value, ResponseID = currentResponse.ID, DocumentType = DTO.Enums.RequestDocumentType.AttachmentInput
                        });
                    }
                }

                _entity.Status = DTO.Enums.RequestStatuses.Submitted;

                await db.SaveChangesAsync();

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

                await SetRequestStatus(DTO.Enums.RequestStatuses.Submitted);

                await MarkTaskComplete(task);

                await NotifyRequestStatusChanged(DTO.Enums.RequestStatuses.AwaitingRequestApproval, DTO.Enums.RequestStatuses.Submitted);

                return(new CompletionResult
                {
                    ResultID = ApproveResultID
                });
            }
            else if (activityResultID.Value == RejectResultID)
            {
                //rejecting prior to submission terminates the request.

                foreach (var dm in _entity.DataMarts.Where(dm => dm.Status == DTO.Enums.RoutingStatus.AwaitingRequestApproval))
                {
                    dm.Status = DTO.Enums.RoutingStatus.RequestRejected;
                }

                await db.SaveChangesAsync();

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

                _entity.RejectedByID = _workflow.Identity.ID;
                _entity.RejectedOn   = DateTime.UtcNow;
                //Update the workflow activity to request composition
                _entity.WorkFlowActivityID = DefaultWorkflowConfiguration.NewRequestActivityID;

                await SetRequestStatus(DTO.Enums.RequestStatuses.RequestRejected);

                //create a completed task to show the request was rejected.
                PmnTask rejectedTask = db.Actions.Add(PmnTask.CreateForWorkflowActivity(_entity.ID, DefaultWorkflowConfiguration.NewRequestActivityID, _workflow.ID, db));
                rejectedTask.Subject = "Request Rejected Prior to Submission";
                rejectedTask.Status  = DTO.Enums.TaskStatuses.InProgress;

                if (!data.IsNullOrEmpty())
                {
                    rejectedTask.Body = data.ToStringEx();

                    var cmt = db.Comments.Add(new Comment
                    {
                        CreatedByID = _workflow.Identity.ID,
                        ItemID      = _entity.ID,
                        Text        = data.ToStringEx()
                    });

                    db.CommentReferences.Add(new CommentReference {
                        CommentID = cmt.ID,
                        Type      = DTO.Enums.CommentItemTypes.Task,
                        ItemTitle = rejectedTask.Subject,
                        ItemID    = rejectedTask.ID
                    });
                }

                await MarkTaskComplete(task);

                await NotifyRequestStatusChanged(DTO.Enums.RequestStatuses.AwaitingRequestApproval, DTO.Enums.RequestStatuses.RequestRejected);

                return(null);
            }
            else
            {
                throw new NotSupportedException(CommonMessages.ActivityResultNotSupported);
            }
        }
示例#4
0
        public override async Task <CompletionResult> Complete(string data, Guid?activityResultID)
        {
            if (!activityResultID.HasValue)
            {
                throw new ArgumentNullException(CommonMessages.ActivityResultIDRequired);
            }

            var task = await PmnTask.GetActiveTaskForRequestActivityAsync(_workflow.Entity.ID, ID, db);

            if (task == null)
            {
                task = db.Actions.Add(PmnTask.CreateForWorkflowActivity(_workflow.Entity.ID, ID, _workflow.ID, db));
            }

            if (activityResultID.Value == SaveResultID)
            {
                return(new CompletionResult
                {
                    ResultID = SaveResultID
                });
            }

            if (activityResultID.Value == EditRoutingStatusResultID)
            {
                var dataMarts = Newtonsoft.Json.JsonConvert.DeserializeObject <IEnumerable <RoutingChangeRequestModel> >(data);
                await UpdateDataMartRoutingStatus(dataMarts);

                return(new CompletionResult
                {
                    ResultID = EditRoutingStatusResultID
                });
            }
            else if (activityResultID.Value == RoutingsBulkEditID)
            {
                return(new CompletionResult
                {
                    ResultID = RoutingsBulkEditID
                });
            }
            else if (activityResultID.Value == RemoveDataMartsResultID)
            {
                Guid[] guids    = data.Split(',').Select(s => Guid.Parse(s)).ToArray();
                var    routings = await db.RequestDataMarts.Where(dm => guids.Contains(dm.ID)).ToArrayAsync();

                foreach (var routing in routings)
                {
                    routing.Status = DTO.Enums.RoutingStatus.Canceled;
                }

                await LogTaskModified();

                await db.SaveChangesAsync();

                var originalStatus = _entity.Status;
                await db.SaveChangesAsync();

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

                if (originalStatus != DTO.Enums.RequestStatuses.Complete && _entity.Status == DTO.Enums.RequestStatuses.Complete)
                {
                    await NotifyRequestStatusChanged(originalStatus, DTO.Enums.RequestStatuses.Complete);
                }
            }
            else if (activityResultID.Value == AddDataMartsResultID)
            {
                DTO.QueryComposer.QueryComposerRequestDTO requestDTO = Newtonsoft.Json.JsonConvert.DeserializeObject <DTO.QueryComposer.QueryComposerRequestDTO>(_entity.Query);
                var modularTerm = requestDTO.Where.Criteria.SelectMany(c => c.Terms.Where(t => t.Type == SimpleModularProgramWorkflowConfiguration.ModularProgramTermID)).FirstOrDefault();
                var termValues  = Newtonsoft.Json.JsonConvert.DeserializeObject <ModularProgramTermValues>(modularTerm.Values["Values"].ToString());

                string[] datamartIDs = data.Split(',');

                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 guid in datamartIDs)
                {
                    Guid dmGuid = new Guid(guid);

                    var dm = RequestDataMart.Create(_entity.ID, dmGuid, _workflow.Identity.ID);
                    dm.Status   = DTO.Enums.RoutingStatus.Submitted;
                    dm.DueDate  = _entity.DueDate;
                    dm.Priority = _entity.Priority;
                    _entity.DataMarts.Add(dm);

                    Response rsp = dm.Responses.OrderByDescending(r => r.Count).FirstOrDefault();
                    //add the request document associations
                    foreach (var revisionSetID in termValues.Documents.Select(d => d.RevisionSetID))
                    {
                        db.RequestDocuments.Add(new RequestDocument {
                            DocumentType = DTO.Enums.RequestDocumentType.Input, ResponseID = rsp.ID, RevisionSetID = revisionSetID
                        });
                    }

                    foreach (var attachment in attachments)
                    {
                        db.RequestDocuments.Add(new RequestDocument {
                            RevisionSetID = attachment.RevisionSetID.Value, ResponseID = rsp.ID, DocumentType = DTO.Enums.RequestDocumentType.AttachmentInput
                        });
                    }
                }

                await LogTaskModified();

                await db.SaveChangesAsync();
            }
            //Grouping
            if (activityResultID.Value == GroupResultID)
            {
                GroupingRequestModel model = Newtonsoft.Json.JsonConvert.DeserializeObject <GroupingRequestModel>(data);

                var responses = await db.Responses.Include(r => r.RequestDataMart).Where(r => model.Responses.Any(x => x == r.ID)).ToArrayAsync();

                if (responses.Select(r => r.RequestDataMart.RequestID).Distinct().Count() > 1)
                {
                    throw new ArgumentException("Cannot group responses that come from different requests.");
                }

                Guid[] requestDataMartIDs = responses.Select(rsp => rsp.RequestDataMartID).Distinct().ToArray();
                var    pq = (from rdm in db.RequestDataMarts
                             let permissionID = PermissionIdentifiers.DataMartInProject.GroupResponses.ID
                                                let identityID = _workflow.Identity.ID
                                                                 let acls = db.GlobalAcls.Where(a => a.PermissionID == permissionID && a.SecurityGroup.Users.Any(sgu => sgu.UserID == identityID)).Select(a => a.Allowed)
                                                                            .Concat(db.ProjectAcls.Where(a => a.PermissionID == permissionID && a.SecurityGroup.Users.Any(sgu => sgu.UserID == identityID) && a.Project.Requests.Any(r => r.ID == rdm.RequestID)).Select(a => a.Allowed))
                                                                            .Concat(db.DataMartAcls.Where(a => a.PermissionID == permissionID && a.SecurityGroup.Users.Any(sgu => sgu.UserID == identityID) && a.DataMartID == rdm.DataMartID).Select(a => a.Allowed))
                                                                            .Concat(db.ProjectDataMartAcls.Where(a => a.PermissionID == permissionID && a.SecurityGroup.Users.Any(sgu => sgu.UserID == identityID) && a.Project.Requests.Any(r => r.ID == rdm.RequestID) && a.DataMartID == rdm.DataMartID).Select(a => a.Allowed))
                                                                            .Concat(db.OrganizationAcls.Where(a => a.PermissionID == permissionID && a.SecurityGroup.Users.Any(sgu => sgu.UserID == identityID) && a.Organization.Requests.Any(r => r.ID == rdm.RequestID)).Select(a => a.Allowed))
                                                                            where requestDataMartIDs.Contains(rdm.ID) &&
                                                                            acls.Any() && acls.All(a => a == true)
                                                                            select rdm.ID);

                var allowedResponses = await pq.ToArrayAsync();


                if (allowedResponses.Length != requestDataMartIDs.Length)
                {
                    throw new SecurityException("Insufficient permission to group one or more of the specified responses.");
                }

                if (string.IsNullOrWhiteSpace(model.GroupName))
                {
                    model.GroupName = string.Join(", ", db.Responses.Where(r => model.Responses.Any(x => x == r.ID)).Select(r => r.RequestDataMart.DataMart.Name).Distinct());
                }

                ResponseGroup grouping = db.ResponseGroups.Add(new ResponseGroup(model.GroupName));
                foreach (var response in responses)
                {
                    grouping.Responses.Add(response);
                    response.RequestDataMart.ResultsGrouped = true;
                }

                await LogTaskModified("Grouped results.");

                await db.SaveChangesAsync();
            }
            //Un-grouping
            if (activityResultID.Value == UngroupResultID)
            {
                IEnumerable <Guid> groupID = (from r in data.Split(',')
                                              where !string.IsNullOrWhiteSpace(r)
                                              select Guid.Parse(r.Trim())).ToArray();

                List <Guid> requestDataMartIDs = await db.ResponseGroups.Include(g => g.Responses).Where(g => groupID.Contains(g.ID)).SelectMany(g => g.Responses.Select(r => r.RequestDataMartID)).ToListAsync();

                var pq = (from rdm in db.RequestDataMarts
                          let permissionID = PermissionIdentifiers.DataMartInProject.GroupResponses.ID
                                             let identityID = _workflow.Identity.ID
                                                              let acls = db.GlobalAcls.Where(a => a.PermissionID == permissionID && a.SecurityGroup.Users.Any(sgu => sgu.UserID == identityID)).Select(a => a.Allowed)
                                                                         .Concat(db.ProjectAcls.Where(a => a.PermissionID == permissionID && a.SecurityGroup.Users.Any(sgu => sgu.UserID == identityID) && a.Project.Requests.Any(r => r.ID == rdm.RequestID)).Select(a => a.Allowed))
                                                                         .Concat(db.DataMartAcls.Where(a => a.PermissionID == permissionID && a.SecurityGroup.Users.Any(sgu => sgu.UserID == identityID) && a.DataMartID == rdm.DataMartID).Select(a => a.Allowed))
                                                                         .Concat(db.ProjectDataMartAcls.Where(a => a.PermissionID == permissionID && a.SecurityGroup.Users.Any(sgu => sgu.UserID == identityID) && a.Project.Requests.Any(r => r.ID == rdm.RequestID) && a.DataMartID == rdm.DataMartID).Select(a => a.Allowed))
                                                                         .Concat(db.OrganizationAcls.Where(a => a.PermissionID == permissionID && a.SecurityGroup.Users.Any(sgu => sgu.UserID == identityID) && a.Organization.Requests.Any(r => r.ID == rdm.RequestID)).Select(a => a.Allowed))
                                                                         where requestDataMartIDs.Contains(rdm.ID) &&
                                                                         acls.Any() && acls.All(a => a == true)
                                                                         select rdm.ID);

                var allowedResponses = await pq.ToArrayAsync();


                if (allowedResponses.Length != requestDataMartIDs.Count)
                {
                    throw new SecurityException("Insufficient permission to ungroup routings for the specified request.");
                }

                var groups = await db.ResponseGroups.Include(g => g.Responses).Where(g => groupID.Contains(g.ID)).ToArrayAsync();

                foreach (var group in groups)
                {
                    requestDataMartIDs.AddRange(group.Responses.Select(r => r.RequestDataMartID));
                    group.Responses.Clear();
                    db.ResponseGroups.Remove(group);
                }

                var routings = await db.RequestDataMarts.Where(dm => requestDataMartIDs.Contains(dm.ID)).ToArrayAsync();

                foreach (var routing in routings)
                {
                    routing.ResultsGrouped = false;
                }

                await LogTaskModified("Ungrouped results.");

                await db.SaveChangesAsync();
            }

            if (activityResultID.Value == TerminateResultID)
            {
                _workflow.Entity.CancelledByID = _workflow.Identity.ID;
                _workflow.Entity.CancelledOn   = DateTime.UtcNow;

                task.Status = DTO.Enums.TaskStatuses.Cancelled;
                await db.SaveChangesAsync();

                return(new CompletionResult
                {
                    ResultID = TerminateResultID
                });
            }

            if (activityResultID.Value == RedistributeResultID)
            {
                if (!await db.HasPermissions <Project>(_workflow.Identity, _entity.ProjectID, Lpp.Dns.DTO.Security.PermissionIdentifiers.Project.ResubmitRequests))
                {
                    throw new System.Security.SecurityException(CommonMessages.RequirePermissionToResubmitRequest, Lpp.Dns.DTO.Security.PermissionIdentifiers.Project.ResubmitRequests.GetType());
                }

                //TODO: is this applicable in workflow?
                //bool canSkipSubmissionApproval = await db.HasPermissions<Request>(Workflow.Identity, Request.ID, Lpp.Dns.DTO.Security.PermissionIdentifiers.Request.SkipSubmissionApproval);

                //data will contain a list of routings to resubmit, the ID may also be for a group
                ResubmitRoutingsModel resubmitModel = Newtonsoft.Json.JsonConvert.DeserializeObject <ResubmitRoutingsModel>(data);

                var datamarts = await(
                    from dm in db.RequestDataMarts.Include(dm => dm.Responses)
                    where dm.RequestID == _entity.ID &&
                    dm.Responses.Any(r => resubmitModel.Responses.Contains(r.ID) || (r.ResponseGroupID.HasValue && resubmitModel.Responses.Contains(r.ResponseGroupID.Value)))
                    select dm
                    ).ToArrayAsync();

                //get the previously submitted input RequestDocument links
                var previousInputRequestDocuments = await(from rd in db.RequestDocuments
                                                          where rd.DocumentType == DTO.Enums.RequestDocumentType.Input &&
                                                          resubmitModel.Responses.Contains(rd.ResponseID)
                                                          select new { RequestDataMartID = rd.Response.RequestDataMartID, RevisionSetID = rd.RevisionSetID }).ToArrayAsync();

                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();

                //attachments are associated to the task they were uploaded on, any existing attachment should be included with the routing
                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();

                DateTime reSubmittedOn = DateTime.UtcNow;
                foreach (var dm in datamarts)
                {
                    var response = dm.AddResponse(_workflow.Identity.ID);
                    response.SubmittedOn   = reSubmittedOn;
                    response.SubmitMessage = resubmitModel.ResubmissionMessage;

                    dm.Status = DTO.Enums.RoutingStatus.Resubmitted;

                    foreach (var requestDoc in previousInputRequestDocuments.Where(rd => rd.RequestDataMartID == dm.ID))
                    {
                        db.RequestDocuments.Add(new RequestDocument {
                            ResponseID = response.ID, RevisionSetID = requestDoc.RevisionSetID, DocumentType = DTO.Enums.RequestDocumentType.Input
                        });
                    }

                    foreach (var attachment in attachments)
                    {
                        db.RequestDocuments.Add(new RequestDocument {
                            RevisionSetID = attachment.RevisionSetID.Value, ResponseID = response.ID, DocumentType = DTO.Enums.RequestDocumentType.AttachmentInput
                        });
                    }
                }

                await SetRequestStatus(DTO.Enums.RequestStatuses.Submitted);

                await LogTaskModified();

                await MarkTaskComplete(task);
            }
            else if (activityResultID.Value == CompleteResultID)
            {
                var originalStatus = _entity.Status;
                await SetRequestStatus(DTO.Enums.RequestStatuses.PendingDraftReport);

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

                await MarkTaskComplete(task);
            }
            else if (activityResultID.Value == CompleteWorkflowResultID)
            {
                var originalStatus = _entity.Status;
                if (originalStatus != DTO.Enums.RequestStatuses.Complete && originalStatus != DTO.Enums.RequestStatuses.CompleteWithReport)
                {
                    await SetRequestStatus(DTO.Enums.RequestStatuses.Complete);

                    await NotifyRequestStatusChanged(originalStatus, DTO.Enums.RequestStatuses.Complete);
                }

                await MarkTaskComplete(task);
            }


            return(new CompletionResult
            {
                ResultID = activityResultID.Value
            });
        }
        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));;
        }
示例#6
0
        public override async Task Start(string comment)
        {
            var task = await PmnTask.GetActiveTaskForRequestActivityAsync(_entity.ID, ID, db);

            if (task == null)
            {
                task = db.Actions.Add(PmnTask.CreateForWorkflowActivity(_entity.ID, ID, _workflow.ID, db, CustomTaskSubject));
                await db.SaveChangesAsync();

                var analysisCenterRouting = await db.RequestDataMarts.Include(rdm => rdm.Responses).Where(rdm => rdm.RequestID == _entity.ID && rdm.RoutingType == RoutingType.AnalysisCenter).FirstOrDefaultAsync();

                Lpp.Dns.Data.Response analysisCenterResponse = null;
                if (analysisCenterRouting.Status == RoutingStatus.Draft && analysisCenterRouting.Responses.Count == 1 && analysisCenterRouting.Responses.Where(rsp => rsp.ResponseTime.HasValue == false).Any())
                {
                    //if the initial status of the routing is draft, and there is only a single response assume this is the first time hitting the analysis center.
                    //use the existing response to submit to the analysis center
                    analysisCenterResponse = analysisCenterRouting.Responses.First();
                }
                else if (analysisCenterRouting.Status != RoutingStatus.Draft)
                {
                    analysisCenterRouting.Status = RoutingStatus.Draft;
                }

                if (analysisCenterResponse == null)
                {
                    analysisCenterResponse = analysisCenterRouting.AddResponse(_workflow.Identity.ID);
                }

                if (db.Entry(task).Collection(t => t.References).IsLoaded == false)
                {
                    await db.Entry(task).Collection(t => t.References).LoadAsync();
                }

                if (task.References.Any(tr => tr.ItemID == analysisCenterResponse.ID) == false)
                {
                    //add a reference to the response to be able to link task to iteration
                    task.References.Add(new TaskReference {
                        ItemID = analysisCenterResponse.ID, TaskID = task.ID, Type = TaskItemTypes.Response
                    });
                }

                //use all the dp output documents to be the input documents for the AC routing
                //build a manifest for where the documents are coming from
                List <Lpp.Dns.DTO.QueryComposer.DistributedRegressionAnalysisCenterManifestItem> manifestItems = new List <DTO.QueryComposer.DistributedRegressionAnalysisCenterManifestItem>();
                var documents = await(from rd in db.RequestDocuments
                                      join rsp in db.Responses on rd.ResponseID equals rsp.ID
                                      join rdm in db.RequestDataMarts on rsp.RequestDataMartID equals rdm.ID
                                      join dm in db.DataMarts on rdm.DataMartID equals dm.ID
                                      join doc in db.Documents on rd.RevisionSetID equals doc.RevisionSetID
                                      where rsp.Count == rsp.RequestDataMart.Responses.Max(r => r.Count) &&
                                      rdm.RequestID == _entity.ID &&
                                      rd.DocumentType == RequestDocumentType.Output &&
                                      rdm.RoutingType == RoutingType.DataPartner &&
                                      doc.ID == db.Documents.Where(dd => dd.RevisionSetID == doc.RevisionSetID).OrderByDescending(dd => dd.MajorVersion).ThenByDescending(dd => dd.MinorVersion).ThenByDescending(dd => dd.BuildVersion).ThenByDescending(dd => dd.RevisionVersion).Select(dd => dd.ID).FirstOrDefault()
                                      select new
                {
                    DocumentID            = doc.ID,
                    DocumentKind          = doc.Kind,
                    DocumentFileName      = doc.FileName,
                    ResponseID            = rd.ResponseID,
                    RevisionSetID         = rd.RevisionSetID,
                    RequestDataMartID     = rsp.RequestDataMartID,
                    DataMartID            = rdm.DataMartID,
                    DataPartnerIdentifier = dm.DataPartnerIdentifier,
                    DataMart = dm.Name
                }).ToArrayAsync();

                // further filtering based on if a output filelist document was included needs to be done. Only the files indicated should be passed on to the analysis center
                foreach (var dpDocuments in documents.GroupBy(k => k.RequestDataMartID))
                {
                    var filelistDocument = dpDocuments.Where(d => !string.IsNullOrEmpty(d.DocumentKind) && string.Equals("DistributedRegression.FileList", d.DocumentKind, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
                    if (filelistDocument != null)
                    {
                        //only include the files indicated in the filelist document
                        using (var ds = new Lpp.Dns.Data.Documents.DocumentStream(db, filelistDocument.DocumentID))
                            using (var reader = new System.IO.StreamReader(ds))
                            {
                                //read the header line
                                reader.ReadLine();

                                string line, filename;
                                bool   includeInDistribution = false;
                                while (!reader.EndOfStream)
                                {
                                    line = reader.ReadLine();
                                    string[] split = line.Split(',');
                                    if (split.Length > 0)
                                    {
                                        filename = split[0].Trim();
                                        if (split.Length > 1)
                                        {
                                            includeInDistribution = string.Equals(split[1].Trim(), "1");
                                        }
                                        else
                                        {
                                            includeInDistribution = false;
                                        }

                                        if (includeInDistribution == false)
                                        {
                                            continue;
                                        }

                                        if (!string.IsNullOrEmpty(filename))
                                        {
                                            Guid?revisionSetID = dpDocuments.Where(d => string.Equals(d.DocumentFileName, filename, StringComparison.OrdinalIgnoreCase)).Select(d => d.RevisionSetID).FirstOrDefault();
                                            if (revisionSetID.HasValue)
                                            {
                                                db.RequestDocuments.AddRange(dpDocuments.Where(d => d.RevisionSetID == revisionSetID.Value).Select(d => new RequestDocument {
                                                    DocumentType = RequestDocumentType.Input, ResponseID = analysisCenterResponse.ID, RevisionSetID = d.RevisionSetID
                                                }).ToArray());
                                                manifestItems.AddRange(dpDocuments.Where(d => d.RevisionSetID == revisionSetID.Value).Select(d => new DTO.QueryComposer.DistributedRegressionAnalysisCenterManifestItem
                                                {
                                                    DocumentID            = d.DocumentID,
                                                    DataMart              = d.DataMart,
                                                    DataMartID            = d.DataMartID,
                                                    DataPartnerIdentifier = d.DataPartnerIdentifier,
                                                    RequestDataMartID     = d.RequestDataMartID,
                                                    ResponseID            = d.ResponseID,
                                                    RevisionSetID         = d.RevisionSetID
                                                }).ToArray());
                                            }
                                        }
                                    }
                                }

                                reader.Close();
                            }
                    }
                    else
                    {
                        db.RequestDocuments.AddRange(dpDocuments.Select(d => new RequestDocument {
                            DocumentType = RequestDocumentType.Input, ResponseID = analysisCenterResponse.ID, RevisionSetID = d.RevisionSetID
                        }).ToArray());
                        manifestItems.AddRange(dpDocuments.Select(d => new DTO.QueryComposer.DistributedRegressionAnalysisCenterManifestItem
                        {
                            DocumentID            = d.DocumentID,
                            DataMart              = d.DataMart,
                            DataMartID            = d.DataMartID,
                            DataPartnerIdentifier = d.DataPartnerIdentifier,
                            RequestDataMartID     = d.RequestDataMartID,
                            ResponseID            = d.ResponseID,
                            RevisionSetID         = d.RevisionSetID
                        }).ToArray());
                    }
                }

                //serialize the manifest of dataparter documents to the analysis center
                byte[] buffer;
                using (var ms = new System.IO.MemoryStream())
                    using (var sw = new System.IO.StreamWriter(ms))
                        using (var jw = new Newtonsoft.Json.JsonTextWriter(sw))
                        {
                            Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer();
                            serializer.Serialize(jw, manifestItems);
                            jw.Flush();

                            buffer = ms.ToArray();
                        }

                //create and add the manifest file
                Document analysisCenterManifest = db.Documents.Add(new Document
                {
                    Description  = "Contains information about the input documents and the datamart they came from.",
                    Name         = "Internal: Analysis Center Manifest",
                    FileName     = "manifest.json",
                    ItemID       = task.ID,
                    Kind         = DocumentKind.SystemGeneratedNoLog,
                    UploadedByID = _workflow.Identity.ID,
                    Viewable     = false,
                    MimeType     = "application/json",
                    Length       = buffer.Length
                });

                analysisCenterManifest.RevisionSetID = analysisCenterManifest.ID;

                db.RequestDocuments.Add(new RequestDocument {
                    DocumentType = RequestDocumentType.Input, ResponseID = analysisCenterResponse.ID, RevisionSetID = analysisCenterManifest.RevisionSetID.Value
                });

                await db.SaveChangesAsync();

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

                //post the manifest content
                analysisCenterManifest.SetData(db, buffer);

                //submit the routing
                analysisCenterRouting.Status = analysisCenterResponse.Count > 1 ? RoutingStatus.Resubmitted : RoutingStatus.Submitted;
                await db.SaveChangesAsync();

                //change the status of the request to conducting analysis
                //manually override the request status using sql direct, EF does not allow update of computed
                await db.Database.ExecuteSqlCommandAsync("UPDATE Requests SET Status = @status WHERE ID = @ID", new System.Data.SqlClient.SqlParameter("@status", (int)RequestStatuses.ConductingAnalysis), new System.Data.SqlClient.SqlParameter("@ID", _entity.ID));

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

            if (!string.IsNullOrWhiteSpace(comment))
            {
                var cmt = db.Comments.Add(new Comment
                {
                    CreatedByID = _workflow.Identity.ID,
                    ItemID      = _entity.ID,
                    Text        = comment
                });

                db.CommentReferences.Add(new CommentReference
                {
                    CommentID = cmt.ID,
                    Type      = DTO.Enums.CommentItemTypes.Task,
                    ItemTitle = task.Subject,
                    ItemID    = task.ID
                });

                await db.SaveChangesAsync();
            }
        }