using System; using System.Collections.Generic; using System.Data.Entity; using System.Data.Entity.Infrastructure; using System.Linq; using System.Net; using System.Web; using System.Web.Mvc; using EnVisage.Code; using EnVisage.Code.BLL; using EnVisage.Models; using EnVisage.Models.ProjectDependencies; using jQuery.DataTables.Mvc; using EnVisage.App_Start; using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using FileHelpers; using System.Web.Script.Serialization; using EnVisage.Code.Cache; using EnVisage.Code.Validation; using System.Text; using System.Threading.Tasks; using Kendo.Mvc.UI; using Prevu.Core.Main; namespace EnVisage.Controllers { [Authorize] public class ProjectController : BaseController { #region Private Members private ProjectManager ProjectManager { get; } private IUserManager UserManager { get; } #endregion #region Contructors public ProjectController(ProjectManager projectManager, IUserManager userManager) { ProjectManager = projectManager; UserManager = userManager; } #endregion #region Actions /// /// GET: /Project/ /// /// Empty view [HttpGet] [AreaSecurity(area = Areas.Projects, level = AccessLevel.Read)] public ActionResult Index() { if (!SecurityManager.CheckSecurityObjectPermission(Areas.Projects, AccessLevel.Read)) return Redirect("/"); return View(); } /// /// GET: /Project/ /// /// Empty view [HttpGet] [AreaSecurity(area = Areas.Projects, level = AccessLevel.Read)] public ActionResult Index2() { return View("MyProjectsList"); } public ActionResult MyProjectsList([DataSourceRequest]Kendo.Mvc.UI.DataSourceRequest request) { Guid userId = Guid.Parse(HttpContext.User.Identity.GetUserId()); int totalRecordCount; int searchRecordCount; var projects = new ProjectManager(DbContext).GetProjects4User(userId, false, null, 1, 100000000, "", out totalRecordCount, out searchRecordCount) .Where(x => IsPart(x.Id) == false) .Select(x => new { x.ProjectName, ScenarioName = x.ActiveScenario != null ? x.ActiveScenario.Name : "", ScenarioId = x.ActiveScenario?.Id ?? Guid.Empty, x.Status, Number = x.ProjectNumber, x.Priority, x.Classification, x.Teams, DeadLine = x.Deadline, x.Client, x.Id, isPart = true, Parts = x.ProjectParts.Select(z => new { z.ProjectName, ScenarioName = z.ActiveScenario != null ? z.ActiveScenario.Name : "", ScenarioId = z.ActiveScenario?.Id ?? Guid.Empty, z.Status, Number = z.ProjectNumber, z.Priority, z.Classification, z.Teams, DeadLine = z.Deadline, z.Client, z.Id }) }).ToList(); return Json(projects, JsonRequestBehavior.AllowGet); } public ActionResult MyProjectPartList(Guid ParentId, [DataSourceRequest]Kendo.Mvc.UI.DataSourceRequest request) { var projects = this.DbContext.Projects.Where(x => x.ParentProjectId == ParentId).ToList().Select(x => new { ProjectName = x.Name, ProjectParentId = x.ParentProjectId ?? Guid.Empty, ProjectParentName = x.ParentProject.Name, Status = x.Status.Name, Number = x.ProjectNumber, x.Priority, Classification = x.Type.Name, Teams = GetTeamNames(x.Id), DeadLine = x.Deadline, Client = x.Client.Name, ScenarioName = GetActiveScenarioName(x.Id), ScenarioId = GetActiveScenarioId(x.Id), x.Id }).Where(x => x.ProjectParentId == ParentId).ToList(); return Json(projects, JsonRequestBehavior.AllowGet); } [HttpPost] [AreaSecurity(area = Areas.Projects, level = AccessLevel.Read)] public ActionResult GetScenariosForProject(Guid ProjectId) { List rt = new List(); List projects = new List { ProjectId }; var scenarios = new ScenarioManager(DbContext).GetScenarios4Projects(projects, ScenarioType.Portfolio, null); foreach (var s in scenarios) { rt.Add(new { key = s.Name, value = s.Id }); } return Json(rt, JsonRequestBehavior.AllowGet); } /// /// Returns JSON project list with filters and sort for jQuery DataTables /// [HttpPost] [AreaSecurity(area = Areas.Projects, level = AccessLevel.Read)] public JsonResult Index(JQueryDataTablesModel jQueryDataTablesModel) { int totalRecordCount; int searchRecordCount; var clients = GetProjects(startIndex: jQueryDataTablesModel.iDisplayStart, pageSize: jQueryDataTablesModel.iDisplayLength, sortedColumns: jQueryDataTablesModel.GetSortedColumns(), totalRecordCount: out totalRecordCount, searchRecordCount: out searchRecordCount, searchString: jQueryDataTablesModel.sSearch); return this.DataTablesJson(items: clients, totalRecords: totalRecordCount, totalDisplayRecords: searchRecordCount, sEcho: jQueryDataTablesModel.sEcho); } [HttpGet] [AreaSecurity(area = Areas.Projects, level = AccessLevel.Write)] public ActionResult Copy(Guid? id) { if (id != null && id != Guid.Empty) if (!SecurityManager.CheckProjectPermission(id.Value, AccessLevel.Write)) return RedirectToAccessDenied(); var model = new ProjectModel(); try { var manager = new ProjectManager(DbContext); model = (ProjectModel)manager.Load(id) ?? new ProjectModel(); var projectStatus = DbContext.Status.FirstOrDefault(x => x.Id == model.StatusId); if (projectStatus != null) { if (projectStatus.Probability100) model.Probability = 100; ViewBag.IsProbability100 = projectStatus.Probability100; } else { ViewBag.IsProbability100 = false; } var statuses = DbContext.Status.Select(x => new { x.Id, x.Probability100 }).ToList(); ViewBag.Statuses = new JavaScriptSerializer().Serialize(statuses); } catch (BLLException blEx) { if (blEx.DisplayError) SetErrorScript(message: blEx.Message); else { LogException(blEx); SetErrorScript(); } } catch (Exception exception) { LogException(exception); SetErrorScript(); } model.SaveAsCopy = true; return Edit(model); } // GET: /Project/Edit/5 [HttpGet] [AreaSecurity(area = Areas.Projects, level = AccessLevel.Write)] public ActionResult Edit(Guid? id, Guid? partId, string backUrl, string backName) { if (id != null && id != Guid.Empty) if (!SecurityManager.CheckProjectPermission(id.Value, AccessLevel.Write)) return RedirectToAccessDenied(); var model = new ProjectModel(); try { var manager = new ProjectManager(DbContext); var scenarioManager = new ScenarioManager(DbContext); model = (ProjectModel)manager.Load(id) ?? new ProjectModel(); if (model.ParentProjectId != null && model.ParentProjectId != Guid.Empty) { return RedirectToAction("Edit", "Project", new { id = model.ParentProjectId, partId = model.Id, backUrl, backName }); } if (id == null || Guid.Empty.Equals(id)) { model.ClientId = Guid.Empty; model.Priority = 1; } else { model.ExpandedPartId = partId; var projectIds = new List(); if (model.HasChildren) { foreach (var part in model.Parts) { part.TeamsUsage = manager.GetProjectTeamsUsageInfo(part.Id); projectIds.Add(part.Id); } } else { model.TeamsUsage = manager.GetProjectTeamsUsageInfo(partId ?? id.Value); projectIds.Add(model.Id); } var scenarios = scenarioManager.GetScenarios4Projects(projectIds, ScenarioType.Portfolio, ScenarioStatus.Active); var projectMinStartDate = scenarios.Min(t => t.StartDate); var projectMaxEndDate = scenarios.Max(t => t.EndDate); model.ProjectMinStartDate = projectMinStartDate?.ToShortDateString() ?? string.Empty; model.ProjectMaxEndDate = projectMaxEndDate?.ToShortDateString() ?? string.Empty; } model.BackUrl = !string.IsNullOrEmpty(backUrl) ? backUrl : Url.Action("Index", "Project"); model.BackName = !string.IsNullOrEmpty(backName) ? backName : "projects"; new NotificationManager(null).UpdateNotificationAsViewedOnLoad(Guid.Parse(this.HttpContext.User.Identity.GetID()), model.Id); var scenarios4Notifications = this.DbContext.Scenarios.Where(x => x.ParentId == model.Id && x.Type == (int)ScenarioType.Portfolio).ToList(); foreach (var s in scenarios4Notifications) { new NotificationManager(null).UpdateNotificationAsViewedOnLoad(Guid.Parse(this.HttpContext.User.Identity.GetID()), s.Id); } var statuses = DbContext.Status.Select(x => new { x.Id, x.Probability100 }).ToList(); ViewBag.Statuses = new JavaScriptSerializer().Serialize(statuses); } catch (BLLException blEx) { if (blEx.DisplayError) SetErrorScript(message: blEx.Message); else { LogException(blEx); SetErrorScript(); } } catch (Exception exception) { LogException(exception); SetErrorScript(); } return View(model); } // POST: /Project/Edit/5 // To protect from overposting attacks, please enable the specific properties you want to bind to, for // more details see http://go.microsoft.com/fwlink/?LinkId=317598. [HttpPost] [ValidateAntiForgeryToken] [AreaSecurity(area = Areas.Projects, level = AccessLevel.Write)] public ActionResult Edit(ProjectModel model) { if (model == null || ContentLocker.IsLock("Project", model.Id.ToString(), User.Identity.GetUserName())) return new HttpStatusCodeResult(HttpStatusCode.BadRequest); if (model.Id != Guid.Empty) if (!SecurityManager.CheckProjectPermission(model.Id, AccessLevel.Write)) return RedirectToAccessDenied(); var projectManager = new ProjectManager(DbContext); var projectPartManager = new ProjectPartManager(DbContext); var scenarioManager = new ScenarioManager(DbContext); var fileManager = new FileManager(DbContext); var workflowManager = new WorkFlowManager(DbContext); var udfMan = new UDFManager(DbContext); var statusManager = new StatusManager(DbContext); // Trim model string properties and look if the project is a new one model.TrimStringProperties(); var isNew = Guid.Empty.Equals(model.Id) || model.SaveAsCopy; var userId = SecurityManager.GetUserPrincipal(); #region Remove incorrect propery values //if user converted ordinary project to project with parts we need to convert old project to a "part" and create a parent project for it //so basically we need to set project model's first part a successor of project that now became project with parts so all scenarios, permissions, etc. will be "reassigned" to the first part //technically we just need to assign project ID to the first part and drop the ID of project + remove CompanyId, Projectnumber and Color from newly "added" part (done by ProjectPartModel itself) if (model.Id != Guid.Empty && model.InitialHasChildrenState == false && model.HasChildren) { if (model.Parts.Count == 0) throw new InvalidOperationException(); model.Parts[0].Id = model.Id; model.Id = Guid.Empty; model.InitialHasChildrenState = model.HasChildren; //also need to drop ParentProjectId from all parts foreach (ProjectPartModel pp in model.Parts) pp.ParentProjectId = Guid.Empty; } var model2Save = model.Clone(); model2Save.ClientId = null; var revalidationRequired = false; for (var i = 0; i < model2Save.Parts.Count; i++) { if (model2Save.Parts[i].DeletedPart) { model.Parts.RemoveAt(i); revalidationRequired = true; } } foreach (var part in model2Save.Parts) { part.InternalContacts?.RemoveAll(t => t == Guid.Empty); part.ExternalContacts?.RemoveAll(t => t == Guid.Empty); } if (revalidationRequired) { ModelState.Clear(); TryValidateModel(model); } #endregion var updatedStatus = new Dictionary(); var savedProjects = model.Parts.SelectMany(x => new[] { x.Id, x.ParentProjectId ?? Guid.Empty }) .Where(x => x != Guid.Empty).Distinct(); if (savedProjects.Any()) { var projects = projectManager.GetProjects(savedProjects, true).ToDictionary(x => x.Id); foreach (var part in model.Parts) { var projectId = model.HasChildren ? part.Id : part.ParentProjectId ?? Guid.Empty; if (projectId == Guid.Empty || !projects.ContainsKey(projectId)) continue; var project = projects[projectId]; if (project.StatusId != part.StatusId && part.StatusId != Guid.Empty) updatedStatus.Add(project.Id, part.StatusId); } } if (ModelState.IsValid) { //using (DbContextTransaction transaction = DbContext.Database.BeginTransaction()) //{ var transactionId = Utils.GetOrCreateTransactionId(DbContext, string.Empty); var projectId = model2Save.Id; try { var addedTeams = new List(); foreach (var p in model.Parts) { var id = model.Id; if (model.HasChildren) { id = p.Id; } var status = this.DbContext.Status.Where(x => x.Id == p.StatusId).Select(x => x.Name).FirstOrDefault(); var s = this.DbContext.Scenarios.FirstOrDefault(x => x.ParentId == id && x.Type == (int)ScenarioType.Portfolio);// && x.Status == (int) ScenarioStatus.Active).FirstOrDefault(); if (s != null) { var cmds = workflowManager.GetAvailableCommands(userId, s.Id); foreach (var c in cmds) { if (c.CommandName == status) DoWorkFlowAction(c, s.Id, userId); } } var existingTeams = this.DbContext.Team2Project.Where(y => y.ProjectId == id).Select(z => z.TeamId).ToList() ?? new List(); if (p.AssignedTeams == null) p.AssignedTeams = new List(); if (p.AssignedTeams.Count <= 0) continue; { var newTeams = p.AssignedTeams.Where(x => !existingTeams.Contains(x)).ToList(); foreach (var t in newTeams) { if (addedTeams.Contains(t)) continue; addedTeams.Add(t); var scenarios = this.DbContext.Scenarios.Where(x => x.ParentId == id && x.Type == (int)ScenarioType.Portfolio).ToList(); if (scenarios.Count > 0) { foreach (var scenario in scenarios) { var st = workflowManager.GetCurrentState(scenario.Id); string state = null; if (!string.IsNullOrEmpty(st?.state)) state = st.state; var who = workflowManager.GetContactTeamDetails(t, WorkFlowContactNotificationType.TeamScenarioAdd, state); if (who.Count > 0) { who = who.Distinct().ToList(); new NotificationManager(this.DbContext).CreateTeamAddNotification(who, scenario.Id, 0, true, state); } } } else { var who = workflowManager.GetContactTeamDetails(t, WorkFlowContactNotificationType.TeamScenarioAdd, null); if (who.Count > 0) { who = who.Distinct().ToList(); (new NotificationManager(this.DbContext)).CreateTeamAddNotification(who, id, 0, true, null); } } } } } if (!isNew) { //this situation occurs when we convert project to project with parts (see above). we rewrite ids between "part" and project and Event Logger needs to be aware of this bool bConvertToProjectWithParts = projectId.Equals(Guid.Empty); projectManager.LogProjectEvents(User.Identity.GetUserId(), model2Save, transactionId, bConvertToProjectWithParts); //projectId is Guid.Empty if we just converted project to project with parts. Since we don't track events for added parts yet, it makes no sense //to query DB here to find anything - first "virtual" part becomes real first part of new project with parts and all other parts will be new //CHANGE if we begin to track "part added" event if (!projectId.Equals(Guid.Empty)) { var partItemsToLoad = ProjectManager.LoadProjectItems.PortfolioLabels | ProjectManager.LoadProjectItems.Tags; var partsInDatabase = projectPartManager.GetItemsAsModelWithChildren(projectId, partItemsToLoad); if (partsInDatabase != null) { foreach (var partId in partsInDatabase.Keys) { var partInDatabase = partsInDatabase[partId]; var clientPartModel = model2Save.Parts.FirstOrDefault(x => (x.Id == partId)); if (clientPartModel != null) //part is not deleted projectManager.LogProjectPartsEvents(true, partInDatabase, clientPartModel, userId.ToString(), transactionId, false); } } } } var newProject = projectManager.Save(model2Save); if (isNew) projectManager.LogProjectCreateEvent(newProject, User.Identity.GetUserId(), transactionId); DbContext.SaveChanges(); var statusUpdatepartIds = DbContext.Projects.Where(t => t.ParentProjectId.HasValue && t.ParentProjectId.Value == newProject.Id).Select(t => t.Id).ToList(); statusUpdatepartIds.Add(newProject.Id); foreach (var partId in statusUpdatepartIds) { var p = this.DbContext.Projects.FirstOrDefault(x => x.Id == partId); if (p == null || p.Id == Guid.Empty) continue; var status = this.DbContext.Status.FirstOrDefault(x => x.Id == p.StatusId && x.ResetScenariosToInactive == true); if (status != null && status.Id != Guid.Empty) { var scenarios = this.DbContext.Scenarios.Where(x => x.ParentId == partId && x.Type == (int)ScenarioType.Portfolio).ToList(); foreach (var scenario in scenarios) { scenario.Status = (int)ScenarioStatus.Inactive; this.DbContext.Entry(scenario).State = EntityState.Modified; } } } var partIds = DbContext.Projects.Where(t => t.ParentProjectId.HasValue && t.ParentProjectId.Value == newProject.Id).Select(t => t.Id).ToArray(); //Give user Full Access permissions to the new project var teamIds = new List(); foreach (var part in model2Save.Parts) { if (part.AssignedTeams != null) teamIds.AddRange(part.AssignedTeams); } var existingUsersPermissions = DbContext.ProjectAccesses.Where(t => partIds.Contains(t.ProjectId) || t.ProjectId == newProject.Id) .Select(t => new { t.ProjectId, t.PrincipalId }).ToList(); var users = (from c in DbContext.User2Team where teamIds.Contains(c.TeamId) select c.UserId).Distinct().ToList(); if (!users.Contains(User.Identity.GetID(), StringComparer.OrdinalIgnoreCase)) users.Add(User.Identity.GetID()); foreach (var contributor in users) { if (!existingUsersPermissions.Any(t => t.PrincipalId == new Guid(contributor) && t.ProjectId == newProject.Id)) { DbContext.ProjectAccesses.Add(new ProjectAccess { PrincipalId = new Guid(contributor), ProjectId = newProject.Id, Read = 1, Write = 1 }); } foreach (var partId in partIds) { if (!existingUsersPermissions.Any(t => t.PrincipalId == new Guid(contributor) && t.ProjectId == partId)) { DbContext.ProjectAccesses.Add(new ProjectAccess { PrincipalId = new Guid(contributor), ProjectId = partId, Read = 1, Write = 1 }); } } } if (isNew) { if (model.SaveAsCopy) { #region Copy attachments if (model.Parts != null) { foreach (var part in model.Parts) { var holderId = model.HasChildren ? part.Id : newProject.Id; if (part.Attachments != null) { // we need to copy only existing attachments to new project, not new var existingAttachments = part.Attachments.Where(x => !x.IsNew).ToList(); if (existingAttachments.Count > 0) { part.Attachments = part.Attachments.Where(x => x.IsNew).ToList(); var copiedAttachments = fileManager.CopyPermanentFiles(existingAttachments, holderId, part.GetType()); if (copiedAttachments != null && copiedAttachments.Count > 0) { foreach (var attachment in copiedAttachments) part.Attachments.Add(attachment); } } } if (part.Links != null) { // we need to copy only existing attachments to new project, not new var existingLinks = part.Links.Where(x => !x.IsNew).ToList(); if (existingLinks.Count > 0) { part.Links = part.Links.Where(x => x.IsNew).ToList(); if (existingLinks != null && existingLinks.Count > 0) { foreach (var link in existingLinks) part.Links.Add(link.Copy()); } } } } } #endregion #region copy udfs if (model.UserDefinedFields == null) model.UserDefinedFields = new List(); foreach (var udf in model.UserDefinedFields) { if (udf.Values != null) { udfMan.saveValue(udf.Values.Copy(), udf.Id, newProject.Id, userId); } } #endregion } #region Move attachments to permanent storage if (model.Parts.Count > 0) { foreach (var partModel in model.Parts) { var parentId = partModel.Id; var parentType = partModel.GetType(); if ((model.Parts.Count == 1) && partModel.Id.Equals(Guid.Empty)) { parentId = newProject.Id; parentType = model.GetType(); } if ((partModel.Attachments != null) && (partModel.Attachments.Count > 0)) { var newAttachments = partModel.Attachments.Where(x => x.IsNew).ToList(); var existingAttachments = partModel.Attachments.Where(x => !x.IsNew).ToList(); var undeletedFiles = fileManager.MoveToPermanentStorage(newAttachments, parentId, parentType); if (undeletedFiles != null && undeletedFiles.Count > 0) { var errorMessage = string.Join(", ", undeletedFiles); LogError(string.Format("Temp attachments copied to permanent storage, but some temp files were not deleted: {0}", errorMessage)); } if (!model.SaveAsCopy && (existingAttachments.Count > 0)) fileManager.ChangeFilesParent(existingAttachments, parentId, parentType); } if (partModel.Links != null && (partModel.Links.Count > 0)) { var linksToAdd = partModel.Links.Where(x => x.IsNew).ToList(); if (linksToAdd.Count > 0) { foreach (var l in linksToAdd) { this.DbContext.Attachments.Add(new Attachment() { Id = Guid.NewGuid(), FileName = l.Name, SourceFileName = l.Name, ContentType = "link", Created = DateTime.Now, FileSize = 0, Link = l.Link, ParentId = parentId, ParentType = parentType.FullName }); } } } } } #endregion } if (!isNew && model.Parts.Count > 0 && !model.SaveAsCopy) { #region Update project attachments var partsIds = model.Parts.Select(x => x.Id).ToList(); if (partsIds.Count == 1 && partsIds.First().Equals(Guid.Empty)) { partsIds.Clear(); partsIds.Add(model.Id); } List attachmentsToRemove = fileManager.GetPermanentFilesByHolder(partsIds) as List; foreach (ProjectPartModel partModel in model.Parts) { if ((partModel.Attachments != null) && (partModel.Attachments.Count > 0)) { var foundAttachments = partModel.Attachments.Where(x => !x.IsNew).Select(y => y.Id); attachmentsToRemove.RemoveAll(x => foundAttachments.Contains(x)); var attachmentsToAdd = partModel.Attachments.Where(x => x.IsNew).ToList(); Guid holderId = partModel.Id; System.Type holderType = partModel.GetType(); if (holderId.Equals(Guid.Empty) && (model.Parts.Count == 1) && !model.Id.Equals(Guid.Empty)) { holderId = model.Id; holderType = model.GetType(); } if (attachmentsToAdd.Count > 0) { var undeletedFiles = fileManager.MoveToPermanentStorage(attachmentsToAdd, holderId, holderType); if (undeletedFiles != null && undeletedFiles.Count > 0) { var errorMessage = string.Join(", ", undeletedFiles); LogError(String.Format("Temp attachments copied to permanent storage, but some temp files were not deleted: {0}", errorMessage)); } } } } if (attachmentsToRemove.Count > 0) fileManager.DeletePermanentFiles(attachmentsToRemove, true); #endregion #region Links partsIds = model.Parts.Select(x => x.Id).ToList(); if (partsIds.Count == 1 && partsIds.First().Equals(Guid.Empty)) { partsIds.Clear(); partsIds.Add(model.Id); } List linksToRemove = this.DbContext.Attachments.Where(x => partsIds.Contains(x.ParentId) && !string.IsNullOrEmpty(x.Link)).Select(x => x.Id).ToList(); foreach (ProjectPartModel partModel in model.Parts) { if ((partModel.Links != null) && (partModel.Links.Count > 0)) { var foundLinks = partModel.Links.Where(x => !x.IsNew).Select(y => y.Id); linksToRemove.RemoveAll(x => foundLinks.Contains(x)); var linksToAdd = partModel.Links.Where(x => x.IsNew).ToList(); Guid holderId = partModel.Id; System.Type holderType = partModel.GetType(); if (holderId.Equals(Guid.Empty) && (model.Parts.Count == 1) && !model.Id.Equals(Guid.Empty)) { holderId = model.Id; holderType = model.GetType(); } if (linksToAdd.Count > 0) { foreach (var l in linksToAdd) { this.DbContext.Attachments.Add(new Attachment() { Id = Guid.NewGuid(), FileName = l.Name, SourceFileName = l.Name, ContentType = "link", Created = DateTime.Now, FileSize = 0, Link = l.Link, ParentId = holderId, ParentType = holderType.FullName }); } } } } if (linksToRemove.Count > 0) { foreach (var l in linksToRemove) { var link = this.DbContext.Attachments.Where(x => x.Id == l).FirstOrDefault(); if (link != null) { this.DbContext.Attachments.Remove(link); this.DbContext.Entry(link).State = EntityState.Deleted; } } } #endregion } #region tags if (model.Parts != null) { foreach (var part in model.Parts) { var holderId = model.HasChildren ? part.Id : newProject.Id; var tagObjsInDb = DbContext.TagLinks.Where(x => x.ParentID == holderId).ToList(); if (part.ProjectTags == null) part.ProjectTags = new List(); if (part.PortfolioTags == null) part.PortfolioTags = new List(); //remove any tags from db that do not exist in collection returned from edit form (they were deleted) foreach (var tagObjInDb in tagObjsInDb) { switch (tagObjInDb.TagLinkType) { case (int)TagType.Portfolio: if (part.PortfolioTags.Where(x => x == tagObjInDb.TagID && tagObjInDb.TagLinkType == (int)TagType.Portfolio).ToList().Count == 0) DbContext.TagLinks.Remove(tagObjInDb); break; case (int)TagType.Project: if (part.ProjectTags.Where(x => x == tagObjInDb.TagID && tagObjInDb.TagLinkType == (int)TagType.Project).ToList().Count == 0) DbContext.TagLinks.Remove(tagObjInDb); break; } } //add new portfolio tag link records if (part.PortfolioTags != null) { foreach (var portTagId in part.PortfolioTags) { if (portTagId != Guid.Empty) { var tag = this.DbContext.TagLinks.Where(x => x.TagID == portTagId && x.ParentID == holderId).FirstOrDefault(); if (tag == null || tag.Id == Guid.Empty) { tag = new TagLink { Id = Guid.NewGuid(), ParentID = holderId, TagID = portTagId, TagLinkType = (int)TagType.Portfolio }; this.DbContext.TagLinks.Add(tag); } } } //add new project tag link records foreach (var projTagId in part.ProjectTags) { if (projTagId != Guid.Empty) { var tag = this.DbContext.TagLinks.Where(x => x.TagID == projTagId && x.ParentID == holderId).FirstOrDefault(); if (tag == null || tag.Id == Guid.Empty) { tag = new TagLink { Id = Guid.NewGuid(), ParentID = holderId, TagID = projTagId, TagLinkType = (int)TagType.Project }; this.DbContext.TagLinks.Add(tag); } } } } } } #endregion #region UDFS if (model.UserDefinedFields == null) model.UserDefinedFields = new List(); foreach (var udf in model.UserDefinedFields) { if (udf.Values != null) { udfMan.saveValue(udf.Values, udf.Id, newProject.Id, userId); } } #endregion DbContext.SaveChanges(); //transaction.Commit(); Task.Run(() => AuditProxy.CommitHistoryChanges(transactionId, userId.ToString())); Task.Run(() => AuditProxy.CommitEventChanges(transactionId)); #region Update workflow statuses if (updatedStatus.Any()) { try { var updatedProjects = updatedStatus.Keys.ToList(); var scenarios = scenarioManager.GetScenarios4Projects(updatedProjects, null, null, false, true) .GroupBy(x => x.ParentId.Value) .ToDictionary(x => x.Key, g => g.ToList()); var statuses = statusManager.GetStatuses(updatedStatus.Values, true).ToDictionary(x => x.Id); foreach (var partId in updatedProjects) { var part = model.Parts.Where(x => x.Id == partId || (x.Id == Guid.Empty && x.ParentProjectId == partId)).FirstOrDefault(); var status = statuses.ContainsKey(part.StatusId) ? statuses[part.StatusId] : null; var partScenarios = scenarios.ContainsKey(partId) ? scenarios[partId] : null; if (status != null && !string.IsNullOrWhiteSpace(status.WorkFlowState) && partScenarios != null) { foreach (var scenario in partScenarios) { if (workflowManager.isProcessExists(scenario.Id)) { var state = workflowManager.GetCurrentState(scenario.Id); var schemeName = workflowManager.getScenarioSchemeName(scenario.Id); var states = workflowManager.getStatesForProcess(schemeName); if ((state == null || state.state != status.WorkFlowState) && states.Any(x => x.state == status.WorkFlowState)) workflowManager.SetState(userId, scenario.Id, null, new WorkFlowState() { state = status.WorkFlowState, Selected = true, HasChanges = true }); } } } (new NotificationManager(null)).RemoveNotification(userId, partId); if (part.ParentProjectId.HasValue && part.ParentProjectId.Value != Guid.Empty) (new NotificationManager(null)).RemoveNotification(userId, part.ParentProjectId.Value); } } catch (Exception wfstatEx) { LogException(wfstatEx); } } #endregion new ProjectAccessCache().Invalidate(); ContentLocker.RemoveLock("Project", model.Id.ToString(), User.Identity.GetUserName()); return !model.SaveAsCopy ? (model2Save.ContinueToScenarios ? RedirectToAction("Edit", new { id = newProject.Id, ptab = model.HasChildren ? "scenarios" : "newscenario" }) : RedirectToAction("Edit", "Project", new { id = newProject.Id })) : RedirectToAction("Edit", "Project", new { id = newProject.Id }); } catch (BLLException blEx) // handle any system specific error { //transaction.Rollback(); AuditProxy.ClearHistoryChanges(transactionId); AuditProxy.ClearEventChanges(transactionId); // display error message if required if (blEx.DisplayError) ModelState.AddModelError(string.Empty, blEx.Message); else // if display not requried then display modal form with general error message { LogException(blEx); SetErrorScript(); } } catch (Exception exception) // handle any unexpected error { //transaction.Rollback(); AuditProxy.ClearHistoryChanges(transactionId); AuditProxy.ClearEventChanges(transactionId); LogException(exception); SetErrorScript(); } //} } if (model.Id != null && model.Id != Guid.Empty) { model.Scenarios = new List(); var projDb = DbContext.Projects.FirstOrDefault(x => x.Id == model.Id); foreach (var childProject in projDb.ChildProjects.OrderBy(pp => pp.PartNum)) { foreach (var scenario in childProject.Scenarios) { if (scenario.Type != ScenarioType.Actuals.GetHashCode()) model.ScenariosCount++; model.Scenarios.Add((ScenarioTabModel)scenario); } } } // return empty model with validation messages (if any) var statusesWithProb100 = DbContext.Status.Select(x => new { x.Id, x.Probability100 }).ToList(); ViewBag.Statuses = new JavaScriptSerializer().Serialize(statusesWithProb100); return View(model); } [AreaSecurity(area = Areas.Projects, level = AccessLevel.Write)] public ActionResult AddPart(ProjectPartModel model, int count) { try { if (ContentLocker.IsLock("Project", (model.ParentProjectId ?? Guid.Empty).ToString(), User.Identity.GetUserName())) return new HttpStatusCodeResult(HttpStatusCode.BadRequest); if (model.ParentProjectId.HasValue && model.ParentProjectId != Guid.Empty) if (!SecurityManager.CheckProjectPermission(model.ParentProjectId.Value, AccessLevel.Write)) return new HttpStatusCodeResult(HttpStatusCode.Unauthorized); //ENV-680. As we pass something to the action method, ModelState object is being generated and passed items being automatically validated //The issue is - we pass ProjectPartModel instance with empty values and it is being validated and partial view being rendered with validation errors //(for now ClientId and Priority are invalid). This it a standard MVC behavior and we cannot change that, so we have two options: //1. reset the validation on the client side manipulating jQuery unobtrusive validation, but this will drop all the validation errors from the entire form // and not just the part we've added //2. clear errors in the ModelState manually - ModelState is not preserved during roundtrips so we're just dropping it now and validation // still performs on the project save //Option 2 seems to be much better choice here so here is the magic: foreach (var key in ModelState.Keys) { ModelState[key].Errors.Clear(); } if (model.PortfolioTags == null) model.PortfolioTags = new List(); if (model.ProjectTags == null) model.ProjectTags = new List(); if (model.WorkFlowContacts == null) model.WorkFlowContacts = new List(); if (model.Links == null) model.Links = new List(); return PartialView("~/Views/Shared/EditorTemplates/ProjectPartModel.cshtml", model); } catch (BLLException blEx) // handle any system specific error { // display error message if required if (blEx.DisplayError) SetErrorScript(message: blEx.Message); else // if display not requried then display modal form with general error message { LogException(blEx); SetErrorScript(); } } catch (Exception exception) // handle any unexpected error { LogException(exception); SetErrorScript(); } return new EmptyResult(); } public ActionResult NewLink() { return View(new AttachmentModel()); } // GET: /Project/Delete/5 [HttpGet] [AreaSecurity(area = Areas.Projects, level = AccessLevel.Write)] public ActionResult Delete(Guid? id) { if (id == null || id == Guid.Empty) return new HttpStatusCodeResult(HttpStatusCode.BadRequest); if (!SecurityManager.CheckProjectPermission(id.Value, AccessLevel.Write)) return RedirectToAccessDenied(); var model = new ProjectModel(); try { var manager = new ProjectManager(DbContext); model = (ProjectModel)manager.Load(id); if (model == null) return HttpNotFound(); var transactionId = DbContext.GetClientConnectionId(); manager.LogProjectDeleteEvent(model, User.Identity.GetUserId(), transactionId); Task.Run(() => AuditProxy.CommitEventChanges(transactionId)); } catch (BLLException blEx) { if (blEx.DisplayError) SetErrorScript(message: blEx.Message); else { LogException(blEx); SetErrorScript(); } } catch (Exception exception) { LogException(exception); SetErrorScript(); } return View(model); } // POST: /Project/Delete/5 [HttpPost, ActionName("Delete")] [ValidateAntiForgeryToken] [AreaSecurity(area = Areas.Projects, level = AccessLevel.Write)] public ActionResult Delete(ProjectModel model) { if (ContentLocker.IsLock("Project", model.Id.ToString(), User.Identity.GetUserName())) return new HttpStatusCodeResult(HttpStatusCode.BadRequest); if (!SecurityManager.CheckProjectPermission(model.Id, AccessLevel.Write)) return RedirectToAccessDenied(); var noteMan = new NoteManager(this.DbContext); var manager = new ProjectManager(DbContext); var dbObj = manager.Load(model.Id, false); if (dbObj == null) return HttpNotFound(); IList holders = manager.GetSubprojectsAndParts(dbObj); FileManager fileMngr = new FileManager(DbContext); fileMngr.QueuePermanentFilesToDelete(holders); foreach (var s in dbObj.Scenarios) { noteMan.RemoveNotesForDomain(s.Id); } var type = DbContext.Types.FirstOrDefault(x => x.Id == dbObj.TypeId && x.NotifyOnProjectDelete == true); var status = DbContext.Status.FirstOrDefault(x => x.Id == dbObj.StatusId && x.NotifyOnProjectDelete == true); (DbContext as IObjectContextAdapter).ObjectContext.ExecuteStoreCommand(string.Format("exec sp_DeleteProject '{0}'", dbObj.Id)); DbContext.SaveChanges(); if (type != null || status != null) (new NotificationManager(null)).SendProjectChangeNotifications(dbObj, type, status, EntityState.Deleted, null); fileMngr.DeleteQueuedFiles(true); ContentLocker.RemoveLock("Project", dbObj.Id.ToString(), User.Identity.GetUserName()); return RedirectToAction("Index"); } [HttpGet] [AreaSecurity(area = Areas.ImportActuals, level = AccessLevel.Read)] public ActionResult ImportActuals(Guid? id) { ImportActualsModel model = null; return View(model); } // POST: /Project/Import/5 [HttpPost, ActionName("ImportActuals")] [AreaSecurity(area = Areas.ImportActuals, level = AccessLevel.Write)] public ActionResult ImportActuals(ImportActualsModel model, HttpPostedFileBase fileUpload) { if (model == null || model.Id == Guid.Empty) { var file = fileUpload; if (file == null || file.ContentLength < 1) { ModelState.AddModelError("", @"File was not loaded"); return View(); } using (var reader = new StreamReader(file.InputStream)) { try { var engine = new FileHelperEngine(); ActualsImportRow[] dataRead = engine.ReadStream(reader); var importer = new ImportActuals(); string log = string.Empty; model = importer.ProcessImport(dataRead, Request["firstRowHeaders"] == "on", Request["zeroOut"] == "on", Request["uomHours"] == "on", User.Identity.GetUserName(), out log); ViewBag.ImportResult = model.ImportSuccessful; ViewBag.ImportLog = log; return View(model); } catch (Exception c) { LogException(c); ModelState.AddModelError("", c.Message); return View(model); } } } else { string log; var importer = new ImportActuals(); var result = importer.CommitImport(model, User.Identity.GetUserName(), out log); //ViewBag.ImportResult = result; ViewBag.ComletedImport = result; ViewBag.ImportLog = log; return View(model); } } [HttpPost] [AreaSecurity(area = Areas.Projects, level = AccessLevel.Write)] public ActionResult AddNote(NoteModel model) { //if (model.ScenarioId != Guid.Empty && ContentLocker.IsLock("Scenarios", model.ScenarioId.ToString(), User.Identity.GetUserName())) // return new HttpStatusCodeResult(HttpStatusCode.BadRequest); model.TrimStringProperties(); if (ModelState.IsValid) { try { using (var noteManager = new NoteManager()) { model.NoteType = NoteType.Project.GetHashCode(); model.Id = Guid.NewGuid(); noteManager.Save(model); } } catch (BLLException blEx) // handle any system specific error { // display error message if required if (blEx.DisplayError) ModelState.AddModelError(string.Empty, blEx.Message); else // if display not requried then display modal form with general error message { LogException(blEx); SetErrorScript(); } } catch (Exception exception) // handle any unexpected error { LogException(exception); SetErrorScript(); } } UriBuilder builder = new UriBuilder(HttpContext.Request.UrlReferrer); var query = HttpUtility.ParseQueryString(builder.Query); query["ptab"] = "notes"; builder.Query = query.ToString(); var url = builder.Path + builder.Query; if (Url.IsLocalUrl(url)) return Redirect(url); return Redirect("/"); } [HttpPost] [AreaSecurity(area = Areas.Projects, level = AccessLevel.Write)] public ActionResult EditNote(NoteModel model) { //if (model.ScenarioId != Guid.Empty && ContentLocker.IsLock("Scenarios", model.ScenarioId.ToString(), User.Identity.GetUserName())) // return new HttpStatusCodeResult(HttpStatusCode.BadRequest); model.TrimStringProperties(); if (ModelState.IsValid) { try { using (var noteManager = new NoteManager()) { var note = noteManager.Load(model.Id); if (note == null) return new HttpStatusCodeResult(HttpStatusCode.BadRequest); model.NoteType = NoteType.Project.GetHashCode(); noteManager.Save(model); } } catch (BLLException blEx) // handle any system specific error { // display error message if required if (blEx.DisplayError) ModelState.AddModelError(string.Empty, blEx.Message); else // if display not requried then display modal form with general error message { LogException(blEx); SetErrorScript(); } } catch (Exception exception) // handle any unexpected error { LogException(exception); SetErrorScript(); } } UriBuilder builder = new UriBuilder(HttpContext.Request.UrlReferrer); var query = HttpUtility.ParseQueryString(builder.Query); query["ptab"] = "notes"; builder.Query = query.ToString(); var url = builder.Path + builder.Query; return Redirect(Url.IsLocalUrl(url) ? url : "/"); } // GET: /User/Edit/5 [AreaSecurity(area = Areas.Projects, level = AccessLevel.Write)] public ActionResult DeleteNote(string Id) { if (string.IsNullOrEmpty(Id) || Id == "JSVar") { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } var noteId = new Guid(Id); using (var noteManager = new NoteManager()) { var note = noteManager.Load(noteId); if (note == null) return new HttpStatusCodeResult(HttpStatusCode.BadRequest); noteManager.Delete(noteId); } var url = HttpContext.Request.UrlReferrer.PathAndQuery; if (Url.IsLocalUrl(url)) return Redirect(url); return Redirect("/"); } // GET: /User/Edit/5 [AreaSecurity(area = Areas.Projects, level = AccessLevel.Write)] public ActionResult EditNote(string Id) { if (string.IsNullOrEmpty(Id) || Id == "JSVar") { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } var noteId = new Guid(Id); var note = (from c in DbContext.Notes where c.Id == noteId select c).FirstOrDefault(); if (note == null) return new HttpStatusCodeResult(HttpStatusCode.BadRequest); return PartialView("_addNote", (NoteModel)note); } // GET: /User/Edit/5 [AreaSecurity(area = Areas.Projects, level = AccessLevel.Write)] public ActionResult AddNote(string Id) { if (string.IsNullOrEmpty(Id)) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } var parentId = new Guid(Id); return PartialView("_addNote", new NoteModel(parentId)); } [HttpGet] public JsonResult LoadExternalContacts(Guid? clientId, string selectControlId) { return Json(new { contacts = LoadContacts(clientId), selectControlId } , JsonRequestBehavior.AllowGet); } [HttpGet] public JsonResult LoadInternalContacts(Guid? companyId, string selectControlId) { return Json(new { contacts = LoadContacts(companyId), selectControlId } , JsonRequestBehavior.AllowGet); } [HttpGet] public JsonResult LoadCompanyGoals(Guid? companyId, string selectControlId) { return Json(new { goals = Utils.GetStrategicGoals(companyId), selectControlId } , JsonRequestBehavior.AllowGet); } [HttpPost] public async Task GetProjectEvents([DataSourceRequest]Kendo.Mvc.UI.DataSourceRequest request, Guid entityId) { try { string orderBy = "DateCreated"; var isOrderAsc = false; if (request.Sorts.Any()) { orderBy = request.Sorts.First().Member; isOrderAsc = request.Sorts.First().SortDirection == ListSortDirection.Ascending; } var eventsData = await ProjectManager.GetProjectEvents(entityId, request.PageSize, (request.Page - 1) * request.PageSize, orderBy, isOrderAsc); return new SuccessContentJsonResult(Json(eventsData, JsonRequestBehavior.AllowGet)); } catch (BLLException blEx) // handle any system specific error { // display error message if required if (blEx.DisplayError) ModelState.AddModelError(string.Empty, blEx.Message); else // if display not requried then display modal form with general error message { LogException(blEx); ModelState.AddModelError(string.Empty, @"Cannot validate project dependencies. Try again later."); } } catch (Exception exception) // handle any unexpected error { LogException(exception); ModelState.AddModelError(string.Empty, @"Cannot validate project dependencies. Try again later."); } return new FailedJsonResult(ModelState); } #region livelink intergration [HttpGet] public ActionResult Import(string Id) { var man = new IntegrationManager(this.DbContext); var m = man.getModel(IntergrationAccessType.ProjectImport); m.ImportControllerName = "Project"; m.ImportRecordId = Id; return string.IsNullOrEmpty(m.UserId) || string.IsNullOrEmpty(m.DecodedPassword) || string.IsNullOrEmpty(m.Url) ? View(m) : Import(m); } public ActionResult Import(IntegrationConnectionModel m) { var Id = ImportProject(m); return RedirectToAction("Edit", "Project", new { id = Id.ToString() }); } #endregion //function will do autocomplete for project number on the //Edit Project page. It returns a list of unused project numbers from the supt_tbl_ProjectIds [HttpGet] public ActionResult ProjectNumberSearch(string term) { using (var dbContext = new EnVisageEntities()) { var projectIDs = dbContext.supt_tbl_ProjectIds.AsNoTracking().Where(x => x.ProjectID.StartsWith(term)).OrderBy(p => p.ProjectID); var projects = dbContext.Projects.AsNoTracking().OrderBy(p => p.ProjectNumber); var list = from pid in projectIDs join d in projects on pid.ProjectID equals d.ProjectNumber into output from d in output.DefaultIfEmpty() where d == null select new { pid.ProjectID }; return this.Json(list.Select(x => x.ProjectID).ToList(), JsonRequestBehavior.AllowGet); } } #region Manage project dependencies [HttpGet] public ActionResult GetDependencies(Guid sessionKey, Guid? id) { try { if (!id.HasValue) return new HttpNotFoundResult(); var cachedDependencies = new List(); var cache = Session[ProjectManager.EDIT_DEPENDENCY_KEY] as ProjectDependencyCache; if (cache != null) if (cache.ContainsKey(sessionKey)) { var pageCache = cache[sessionKey]; if (pageCache != null) cachedDependencies = pageCache.Select(t => new DependencyChainItem { Id = t.Id, SourceProjectId = t.SourceProjectId, TargetProjectId = t.TargetProjectId, Type = t.Type }).ToList(); } var manager = new ProjectDependencyManager(DbContext); // load dependencies from DB var dbRecords = manager.LoadProjectDependencies(new List { id.Value }); // union db records with records from cache var mergedRecords = dbRecords.Values.Union(cachedDependencies).Distinct(); // build UI model for merged collection var model = manager.BuildDependencyListModel(id.Value, mergedRecords, SecurityManager.GetUserPrincipal()) ?? new ProjectDependencyListModel(); //Logger.Debug("ProjectController.GetDependencies ended"); return Json(model, JsonRequestBehavior.AllowGet); } catch (Exception exception) { LogException(exception); } return new HttpStatusCodeResult(HttpStatusCode.InternalServerError); } [HttpPost] public ActionResult EditDependency(ProjectDependencyModel model) { if (model == null) { ModelState.AddModelError(string.Empty, @"Cannot save project dependency. Try again later."); return new FailedJsonResult(ModelState); } model.TrimStringProperties(); if (ModelState.IsValid) { try { Logger.Debug("EditDependency controller method. Model object:"); var sb = new StringBuilder(); model.DebugObjectProperties(sb); Logger.Debug(sb); var manager = new ProjectDependencyManager(DbContext); // if this is a new project then save new item to session if (Guid.Empty.Equals(model.SourceProjectId) || Guid.Empty.Equals(model.TargetProjectId)) { if (Guid.Empty.Equals(model.SessionKey)) { Logger.Error("Cannot save project dependency because SessionKey is empty"); sb = new StringBuilder(); model.DebugObjectProperties(sb); Logger.Debug(sb); } else { ProjectDependencyCache cache = null; if (Session[ProjectManager.EDIT_DEPENDENCY_KEY] == null) { cache = new ProjectDependencyCache(); Session[ProjectManager.EDIT_DEPENDENCY_KEY] = cache; } if (cache != null && !cache.ContainsKey(model.SessionKey)) cache.Add(model.SessionKey, new List()); var pageCache = cache[model.SessionKey]; var storedItem = pageCache.FirstOrDefault(t => t.Id == model.Id); if (storedItem == null) pageCache.Add(model); } } else { manager.Save(model); if (model.ResolveConflicts != null) manager.ResolveConflicts(model.ResolveConflicts); DbContext.SaveChanges(); } return new SuccessJsonResult(); } catch (BLLException blEx) // handle any system specific error { // display error message if required if (blEx.DisplayError) ModelState.AddModelError(string.Empty, blEx.Message); else // if display not requried then display modal form with general error message { LogException(blEx); ModelState.AddModelError(string.Empty, @"Cannot save project dependency. Try again later."); } } catch (Exception exception) // handle any unexpected error { LogException(exception); ModelState.AddModelError(string.Empty, @"Cannot save project dependency. Try again later."); } } return new FailedJsonResult(ModelState); } [HttpPost] public ActionResult DeleteDependency(Guid id, Guid sessionKey) { if (Guid.Empty.Equals(id) || Guid.Empty.Equals(sessionKey)) { ModelState.AddModelError(string.Empty, @"Cannot delete project dependency. Try again later."); Logger.Error("Cannot delete project dependency. id={0}, sessionKey={1}", id, sessionKey); return new FailedJsonResult(ModelState); } try { var manager = new ProjectDependencyManager(DbContext); manager.Delete(id, User.Identity.GetUserId()); DbContext.SaveChanges(); return new SuccessJsonResult(); } catch (BLLException blEx) // handle any system specific error { // display error message if required if (blEx.DisplayError) ModelState.AddModelError(string.Empty, blEx.Message); else // if display not requried then display modal form with general error message { LogException(blEx); ModelState.AddModelError(string.Empty, @"Cannot delete project dependency. Try again later."); } } catch (Exception exception) // handle any unexpected error { LogException(exception); ModelState.AddModelError(string.Empty, @"Cannot delete project dependency. Try again later."); } return new FailedJsonResult(ModelState); } [HttpGet] public ActionResult GetProjects(short type, Guid projectId, Guid sessionKey) { //Logger.Debug("ProjectController.GetProjects started"); if (Guid.Empty.Equals(projectId) || Guid.Empty.Equals(sessionKey)) { ModelState.AddModelError(string.Empty, @"Cannot load projects. Try again later."); Logger.Error("Cannot load projects. type={0}, projectId={1}, sessionKey={2}", type, projectId, sessionKey); return new HttpStatusCodeResult(HttpStatusCode.InternalServerError); } try { var manager = new ProjectDependencyManager(DbContext); var result = manager.GetAvailableProjects(projectId, sessionKey, SecurityManager.GetUserPrincipal()); return Json(result, JsonRequestBehavior.AllowGet); //Logger.Debug("ProjectController.GetProjects ended"); } catch (Exception exception) // handle any unexpected error { LogException(exception); } //Logger.Debug("ProjectController.GetProjects ended"); return new HttpStatusCodeResult(HttpStatusCode.InternalServerError); } [HttpPost] [ValidateJsonAntiForgeryToken] public ActionResult ValidateDependencyConflicts(DependencyResolveModel model) { if (model == null) { ModelState.AddModelError(string.Empty, @"Cannot save validate project dependency. Try again later."); return new FailedJsonResult(ModelState); } model.TrimStringProperties(); if (ModelState.IsValid) { try { Logger.Debug("ValidateDependencyConflicts controller method. Model object:"); var sb = new StringBuilder(); model.DebugObjectProperties(sb); Logger.Debug(sb); var manager = new ProjectDependencyManager(DbContext); DependencyResolveModel validationResult; manager.ValidateProjects(model, out validationResult); ModelState.Clear(); TryValidateModel(validationResult); return ModelState.IsValid ? new PartialViewJsonResult(true, null, "~/Views/Shared/EditorTemplates/DependencyResolveModel.cshtml", validationResult, ControllerContext, ViewData, TempData) : new PartialViewJsonResult(false, null, "~/Views/Shared/EditorTemplates/DependencyResolveModel.cshtml", validationResult, ControllerContext, ViewData, TempData); } catch (BLLException blEx) // handle any system specific error { // display error message if required if (blEx.DisplayError) ModelState.AddModelError(string.Empty, blEx.Message); else // if display not requried then display modal form with general error message { LogException(blEx); ModelState.AddModelError(string.Empty, @"Cannot validate project dependencies. Try again later."); } } catch (Exception exception) // handle any unexpected error { LogException(exception); ModelState.AddModelError(string.Empty, @"Cannot validate project dependencies. Try again later."); } } return new FailedJsonResult(ModelState); } #endregion #endregion #region Private Methods private string GetActiveScenarioName(Guid ProjectId) { string name = this.DbContext.Scenarios.Where(x => x.ParentId == ProjectId && x.Type == (int)ScenarioType.Portfolio && x.Status == (int)ScenarioStatus.Active).Select(x => x.Name).FirstOrDefault(); return string.IsNullOrEmpty(name) ? "" : name; } private Guid GetActiveScenarioId(Guid projectId) { return DbContext.Scenarios.Where(x => x.ParentId == projectId && x.Type == (int)ScenarioType.Portfolio && x.Status == (int)ScenarioStatus.Active).Select(x => x.Id).FirstOrDefault(); } private bool IsPart(Guid projectId) { return DbContext.Projects.Any(x => x.Id == projectId && x.ParentProjectId != null && x.ParentProjectId != Guid.Empty); } private string GetTeamNames(Guid projectId) { var teams = DbContext.Team2Project.Where(x => x.ProjectId == projectId).Select(x => x.Team.Name).ToList(); string rt = ""; string sep = ""; if (teams.Count == 0) return rt; // var teamnames = this.DbContext.Teams.Where(x => teams.Contains(x.Id)).Select(x => x.Name).ToList(); foreach (var teamname in teams) { rt += sep + teamname; sep = ";"; } return rt; } private IList GetProjects(int startIndex, int pageSize, ReadOnlyCollection sortedColumns, out int totalRecordCount, out int searchRecordCount, string searchString) { var userId = SecurityManager.GetUserPrincipal(); var groupByTeam = UserManager.GetPagePreferencesValue(Url.Action("Index", "Project"), "projectsTable", "groupByTeam", userId); var projectsToDisplay = ProjectManager.GetProjects4User(userId, groupByTeam, sortedColumns[0], startIndex, pageSize, searchString, out totalRecordCount, out searchRecordCount); var projectsIds = projectsToDisplay.Select(x => x.Id); var partsIds = projectsToDisplay.Where(x => x.ProjectParts != null).SelectMany(x => x.ProjectParts).Where(x => x != null).Select(x => x.Id); var projectsWithPartsIds = projectsIds.Union(partsIds).ToList(); var inactiveScenarios = DbContext.Scenarios.AsNoTracking() .Where(s => s.Type == (int)ScenarioType.Portfolio && s.Status == (int)ScenarioStatus.Inactive && s.ParentId.HasValue && projectsWithPartsIds.Contains(s.ParentId.Value)) .Select(x => new { ProjectId = x.ParentId.Value, ScenarioId = x.Id, ScenarioName = x.Name, ScenarioStartDate = x.StartDate, ScenarioEndDate = x.EndDate, }) .AsEnumerable() .GroupBy(x => x.ProjectId) .ToDictionary(x => x.Key, g => g.Select(x => new InactiveScenarioInProjectModel() { Id = x.ScenarioId, Name = x.ScenarioName, StartDate = x.ScenarioStartDate.HasValue ? Utils.ConvertToUnixDate(x.ScenarioStartDate.Value) : (long?)null, EndDate = x.ScenarioEndDate.HasValue ? Utils.ConvertToUnixDate(x.ScenarioEndDate.Value) : (long?)null, }).ToList()); foreach (var projItem in projectsToDisplay) { if (inactiveScenarios.ContainsKey(projItem.Id)) projItem.InactiveScenarios = inactiveScenarios[projItem.Id]; if ((projItem.ProjectParts != null) && projItem.ProjectParts.Count > 0) { foreach (var projPartItem in projItem.ProjectParts) { if (inactiveScenarios.ContainsKey(projPartItem.Id)) projPartItem.InactiveScenarios = inactiveScenarios[projPartItem.Id]; } } } return projectsToDisplay; } private List LoadContacts(Guid? parentId) { if (parentId == null || parentId == Guid.Empty) return new List(); return DbContext.Contacts.Where(c => c.ParentId == parentId).OrderBy(c => c.LastName).Select(c => new ContactModel { Id = c.Id, ParentId = c.ParentId ?? Guid.Empty, FirstName = c.FirstName, LastName = c.LastName, Type = (ContactType)c.Type, Email = c.Email, }).ToList(); } private Guid ImportProject(IntegrationConnectionModel m) { var importMan = new IntegrationManager(DbContext); var model2Save = importMan.ImportProjectFromAPI(IntergrationAccessType.ProjectImport, m, m.ImportRecordId); var pman = new ProjectManager(DbContext); var newProject = pman.Save(model2Save); DbContext.SaveChanges(); var partIds = DbContext.Projects.Where(t => t.ParentProjectId.HasValue && t.ParentProjectId.Value == newProject.Id).Select(t => t.Id).ToArray(); //Give user Full Access permissions to the new project var teamIds = new List(); foreach (var part in model2Save.Parts) { if (part.AssignedTeams != null) teamIds.AddRange(part.AssignedTeams); } var existingUsersPermissions = DbContext.ProjectAccesses.Where(t => partIds.Contains(t.ProjectId) || t.ProjectId == newProject.Id) .Select(t => new { t.ProjectId, t.PrincipalId }).ToList(); var users = DbContext.User2Team.Where(c => teamIds.Contains(c.TeamId)).Select(c => c.UserId).Distinct().ToList(); if (!users.Contains(User.Identity.GetID(), StringComparer.OrdinalIgnoreCase)) users.Add(User.Identity.GetID()); foreach (var contributor in users) { if (!existingUsersPermissions.Any(t => t.PrincipalId == new Guid(contributor) && t.ProjectId == newProject.Id)) { DbContext.ProjectAccesses.Add(new ProjectAccess() { PrincipalId = new Guid(contributor), ProjectId = newProject.Id, Read = 1, Write = 1 }); } foreach (var partId in partIds) { if (!existingUsersPermissions.Any(t => t.PrincipalId == new Guid(contributor) && t.ProjectId == partId)) { DbContext.ProjectAccesses.Add(new ProjectAccess() { PrincipalId = new Guid(contributor), ProjectId = partId, Read = 1, Write = 1 }); } } } return newProject.Id; } private void DoWorkFlowAction(WorkFlowCommandModel cmd, Guid scenarioId, Guid userid) { if (cmd != null) { WorkFlowManager wfman = new WorkFlowManager(DbContext); wfman.ExecuteCommand(scenarioId, cmd.CommandName, userid); } } #endregion } }