public static async Task ConfirmUsersToTaskForWorkflowRequest(PmnTask task, Request request, DataContext db) { //Get all the users that have view task permission but have not been added to the specified task. var query = from ru in db.RequestUsers let pq = db.ProjectRequestTypeWorkflowActivities.Where(a => a.SecurityGroup.Users.Any(u => u.UserID == ru.UserID) && a.PermissionID == PermissionIdentifiers.ProjectRequestTypeWorkflowActivities.ViewTask && a.ProjectID == ru.Request.ProjectID && a.RequestTypeID == ru.Request.RequestTypeID && a.WorkflowActivityID == ru.Request.WorkFlowActivityID) where ru.RequestID == request.ID && pq.Any(a => a.PermissionID == PermissionIdentifiers.ProjectRequestTypeWorkflowActivities.ViewTask) && pq.All(a => a.Allowed) && !db.ActionUsers.Any(tu => tu.TaskID == task.ID && tu.UserID == ru.UserID) select ru; IEnumerable <Guid> usersToAdd = query.Select(r => r.UserID).Distinct(); foreach (var userID in usersToAdd) { //NOTE: by default the users will be added to task as worker. task.Users.Add(new PmnTaskUser { Role = DTO.Enums.TaskRoles.Worker, UserID = userID }); } if (usersToAdd.Any()) { await db.SaveChangesAsync(); } }
public override IEnumerable <AuditLog> ProcessEvents(System.Data.Entity.Infrastructure.DbEntityEntry obj, DataContext db, ApiIdentity identity, bool read) { var document = obj.Entity as Document; if (document == null) { throw new InvalidCastException("The entity being logged is not a Document."); } var logs = new List <AuditLog>(); if ((document.Kind == DTO.Enums.DocumentKind.SystemGeneratedNoLog) || (document.Kind == DTO.Enums.DocumentKind.Request)) { return(logs); } var orgUser = db.Users.Where(u => u.ID == identity.ID).Select(u => new { u.UserName, u.Organization.Acronym }).FirstOrDefault(); var logItem = new Audit.DocumentChangeLog { Description = string.Format("{0} '{1}' has been {2} by {3}", document.ParentDocumentID.HasValue ? "Revision of document": "Document", document.Name, obj.State, (orgUser.Acronym + @"\" + orgUser.UserName)), Reason = obj.State, UserID = identity == null ? Guid.Empty : identity.ID, DocumentID = document.ID, Document = document }; db.LogsDocumentChange.Add(logItem); logs.Add(logItem); //check if associated with a request, if so create a document added for request notification //Overall request document will have request.ID == document.ItemID, task document will have task.ID == document.ItemID PmnTask workflowActivityTask = null; var request = db.Requests.Find(document.ItemID); if (request == null) { var taskReference = db.ActionReferences.Include(tr => tr.Task).Where(tr => tr.TaskID == document.ItemID && tr.Type == TaskItemTypes.Request).FirstOrDefault(); if (taskReference != null) { workflowActivityTask = taskReference.Task; request = db.Requests.Find(taskReference.ItemID); } } if (request != null && obj.State == EntityState.Added) { logs.Add( db.LogsRequestDocumentChange.Add( new Audit.RequestDocumentChangeLog { Description = string.Format("{0} '{1}' for Request: {2} been has added by {3}", (document.ParentDocumentID.HasValue ? "Revision of document" : "Document"), document.Name, request.Name, (orgUser.Acronym + @"\" + orgUser.UserName)), UserID = identity == null ? Guid.Empty : identity.ID, Reason = obj.State, DocumentID = document.ID, RequestID = request.ID, TaskID = workflowActivityTask == null ? null : (Guid?)workflowActivityTask.ID } ) ); } return(logs); }
/// <summary> /// /// </summary> /// <param name="request"></param> /// <returns></returns> async Task FromDataPartner(RequestDataMart reqDM) { //close the current task var currentTask = await PmnTask.GetActiveTaskForRequestActivityAsync(reqDM.Request.ID, reqDM.Request.WorkFlowActivityID.Value, DB); CompleteTask(currentTask); //open new task and set the request to the new activity var task = DB.Actions.Add(PmnTask.CreateForWorkflowActivity(reqDM.Request.ID, ConductAnalysisActivityID, WorkflowID, DB)); reqDM.Request.WorkFlowActivityID = ConductAnalysisActivityID; //create new routing var analysisCenterRouting = await DB.RequestDataMarts.Include(rdm => rdm.Responses).Where(rdm => rdm.RequestID == reqDM.Request.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(IdentityID); } //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 q = 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 == reqDM.Request.ID && rd.DocumentType == RequestDocumentType.Output && rdm.RoutingType == RoutingType.DataPartner && doc.ItemID == rsp.ID && doc.ID == DB.Documents.Where(dd => dd.RevisionSetID == doc.RevisionSetID && doc.ItemID == rsp.ID).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 }; var documents = await(q).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 { var inputDocuments = dpDocuments.Where(d => d.DocumentKind != "DistributedRegression.AdapterEventLog" && d.DocumentKind != "DistributedRegression.TrackingTable"); if (inputDocuments.Count() > 0) { DB.RequestDocuments.AddRange(inputDocuments.Select(d => new RequestDocument { DocumentType = RequestDocumentType.Input, ResponseID = analysisCenterResponse.ID, RevisionSetID = d.RevisionSetID }).ToArray()); manifestItems.AddRange(inputDocuments.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 = IdentityID, Viewable = false, MimeType = "application/json", Length = buffer.Length }); analysisCenterManifest.RevisionSetID = analysisCenterManifest.ID; //TODO:determine if there is a parent document to make the manifest a revision of. If there is update the revisionset id, and version numbers //chances are there should not be unless this is a resubmit for the same task var allTasks = await DB.ActionReferences.Where(tr => tr.ItemID == reqDM.Request.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(); DB.RequestDocuments.Add(new RequestDocument { DocumentType = RequestDocumentType.Input, ResponseID = analysisCenterResponse.ID, RevisionSetID = analysisCenterManifest.RevisionSetID.Value }); foreach (var attachment in attachments) { DB.RequestDocuments.Add(new RequestDocument { RevisionSetID = attachment.RevisionSetID.Value, ResponseID = analysisCenterResponse.ID, DocumentType = DTO.Enums.RequestDocumentType.AttachmentInput }); } 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(); //Check for Job Fail trigger, and update Data Partner Routing to Failed. //Request status will not be affected. if (documents.Any(d => d.DocumentKind == JobFailTriggerFileKind)) { //Reload the entity before updating the status, else EF will report an exception. await DB.Entry(reqDM).ReloadAsync(); reqDM.Status = RoutingStatus.Failed; 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", reqDM.Request.ID)); await DB.Entry(reqDM.Request).ReloadAsync(); }
void CompleteTask(PmnTask task) { task.Status = DTO.Enums.TaskStatuses.Complete; task.EndOn = DateTime.UtcNow; task.PercentComplete = 100d; }
/// <summary> /// /// </summary> /// <param name="request"></param> /// <returns></returns> async Task FromAnalysisCenter(RequestDataMart reqDM) { //close the current task var currentTask = await PmnTask.GetActiveTaskForRequestActivityAsync(reqDM.Request.ID, reqDM.Request.WorkFlowActivityID.Value, DB); currentTask.Status = DTO.Enums.TaskStatuses.Complete; currentTask.EndOn = DateTime.UtcNow; currentTask.PercentComplete = 100d; //open new task and set the request to the new activity var task = DB.Actions.Add(PmnTask.CreateForWorkflowActivity(reqDM.Request.ID, CompleteDistributionActivityID, WorkflowID, DB)); reqDM.Request.WorkFlowActivityID = CompleteDistributionActivityID; //get the documents uploaded by the analysis center 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 rdm.RequestID == reqDM.Request.ID && rdm.RoutingType == RoutingType.AnalysisCenter && rd.DocumentType == RequestDocumentType.Output && rsp.Count == rdm.Responses.Max(r => r.Count) && 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, RevisionSetID = rd.RevisionSetID, DocumentKind = doc.Kind, FileName = doc.FileName }).ToArrayAsync(); if (documents.Any(d => d.DocumentKind == JobFailTriggerFileKind)) { //stop file, end regression. CompleteTask(task); reqDM.Request.WorkFlowActivityID = CompletedActivityID; //Save changes and reload entity //If this is not done, EF throws an exception on updating the status of the Request DataMart. await DB.SaveChangesAsync(); await DB.Entry(reqDM).ReloadAsync(); //Set the routing status to Failed. reqDM.Status = RoutingStatus.Failed; await DB.SaveChangesAsync(); //change the status of the request to Failed //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.Failed), new System.Data.SqlClient.SqlParameter("@ID", reqDM.Request.ID)); return; } if (documents.Any(d => d.DocumentKind == StopProcessingTriggerDocumentKind)) { //stop file, end regression. All the routes should be complete now and the request status should be already in Completed. Just need to update the current activity. CompleteTask(task); reqDM.Request.WorkFlowActivityID = CompletedActivityID; //NOTE: notification of complete request will be handled outside of the helper } else { if (documents.Length > 0) {//ASPE-605: change the association of the document owner from the analysis center response to the complete distribution task (current task). //This is to support showing the AC documents in the task documents tab. //add a reference to the response to the current task so that we can track back to the source. try { Guid currentResponseID = await DB.Responses.Where(rsp => rsp.RequestDataMartID == reqDM.ID && rsp == rsp.RequestDataMart.Responses.OrderByDescending(rrsp => rrsp.Count).FirstOrDefault()).Select(rsp => rsp.ID).FirstAsync(); if (DB.Entry(currentTask).Collection(t => t.References).IsLoaded == false) { await DB.Entry(currentTask).Collection(t => t.References).LoadAsync(); } if (currentTask.References.Any(tr => tr.ItemID == currentResponseID) == false) { task.References.Add(new TaskReference { TaskID = currentTask.ID, ItemID = currentResponseID, Type = TaskItemTypes.Response }); } }catch { //do not kill processing if this fails, eventlog builder has contingencies to handle if the task reference to the response is not set. } StringBuilder query = new StringBuilder(); query.Append("UPDATE Documents SET ItemID='" + currentTask.ID.ToString("D") + "'"); query.Append(" WHERE ID IN ("); query.Append(string.Join(",", documents.Select(d => string.Format("'{0:D}'", d.DocumentID)))); query.Append(")"); await DB.Database.ExecuteSqlCommandAsync(query.ToString()); } //the output files from the analysis center will now become the input files for each active dataparter route List <Guid> responseIDs = new List <Guid>(); var allTasks = await DB.ActionReferences.Where(tr => tr.ItemID == reqDM.Request.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(); var dataPartnerRoutes = await DB.RequestDataMarts.Include(rdm => rdm.Responses).Where(rdm => rdm.RequestID == reqDM.Request.ID && rdm.Status != RoutingStatus.Canceled && rdm.RoutingType == RoutingType.DataPartner).ToArrayAsync(); foreach (var route in dataPartnerRoutes) { var response = route.AddResponse(IdentityID); responseIDs.Add(response.ID); route.Status = response.Count > 1 ? RoutingStatus.Resubmitted : RoutingStatus.Submitted; foreach (var attachment in attachments) { DB.RequestDocuments.Add(new RequestDocument { RevisionSetID = attachment.RevisionSetID.Value, ResponseID = response.ID, DocumentType = DTO.Enums.RequestDocumentType.AttachmentInput }); } } var filelistDocument = documents.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 = documents.Where(d => string.Equals(d.FileName, filename, StringComparison.OrdinalIgnoreCase)).Select(d => d.RevisionSetID).FirstOrDefault(); if (revisionSetID.HasValue) { DB.RequestDocuments.AddRange(responseIDs.Select(rspID => new RequestDocument { DocumentType = RequestDocumentType.Input, ResponseID = rspID, RevisionSetID = revisionSetID.Value }).ToArray()); } } } } reader.Close(); } } else { var requestDocuments = (from d in documents from responseID in responseIDs where d.DocumentKind != "DistributedRegression.AdapterEventLog" && d.DocumentKind != "DistributedRegression.TrackingTable" select new RequestDocument { DocumentType = RequestDocumentType.Input, ResponseID = responseID, RevisionSetID = d.RevisionSetID }).ToArray(); if (requestDocuments.Length > 0) { DB.RequestDocuments.AddRange(requestDocuments); } } } await DB.SaveChangesAsync(); }