using System; using System.Collections.Generic; using System.Linq; using EnVisage.Models; using System.Data.Entity; using System.Threading.Tasks; namespace EnVisage.Code.BLL { public class ViewManager : ManagerBase { public ViewManager(EnVisageEntities dbContext) : base(dbContext) { } public override View Save(ViewModel model) { throw new NotImplementedException("Use Save(model, userId) method instead"); } public View Save(ViewModel model, Guid userId) { var availableCompanies = GetVisibleToUserCompanies(userId); var view = base.Save(model); if (Guid.Empty.Equals(model.Id)) { #region Create new View if (model.Watchers != null) { foreach (var watcherId in model.Watchers) { var user2View = DbContext.User2View.Create(); user2View.Id = Guid.NewGuid(); user2View.ViewId = view.Id; user2View.UserId = watcherId; DbContext.User2View.Add(user2View); } } if (model.Teams != null) { foreach (var teamId in model.Teams) { var team2View = DbContext.Team2View.Create(); team2View.Id = Guid.NewGuid(); team2View.ViewId = view.Id; team2View.TeamId = teamId; DbContext.Team2View.Add(team2View); } } if (model.Companies != null) { // Filter companies: exclude child ones from list, if parent company selected var companiesFiltered = this.FilterCompanyList(model.Companies.ToList(), availableCompanies); foreach (var companyId in companiesFiltered) { var comp2View = DbContext.Company2View.Create(); comp2View.Id = Guid.NewGuid(); comp2View.ViewId = view.Id; comp2View.CompanyId = companyId; DbContext.Company2View.Add(comp2View); } } #endregion } else { #region Update existing View var currentWatchers = DbContext.User2View.Where(x => x.ViewId == model.Id).ToList(); var usersToRemove = currentWatchers.Where(x => model.Watchers == null || !model.Watchers.Contains(x.UserId)).ToList(); usersToRemove.ForEach(x => DbContext.Entry(x).State = EntityState.Deleted); if (model.Watchers != null) { var watchersToAdd = model.Watchers.Where(c => currentWatchers.All(x => x.UserId != c)).ToList(); foreach (var watcherId in watchersToAdd) { var user2View = DbContext.User2View.Create(); user2View.Id = Guid.NewGuid(); user2View.ViewId = view.Id; user2View.UserId = watcherId; DbContext.Entry(user2View).State = EntityState.Added; } } var currentTeams = DbContext.Team2View.Where(x => x.ViewId == view.Id).ToList(); var teamsToRemove = currentTeams.Where(x => model.Teams == null || !model.Teams.Contains(x.TeamId)).ToList(); teamsToRemove.ForEach(x => DbContext.Entry(x).State = EntityState.Deleted); if (model.Teams != null) { var teamsToAdd = model.Teams.Where(c => !currentTeams.Select(x => x.TeamId).Contains(c)).ToList(); foreach (var teamId in teamsToAdd) { var team2View = DbContext.Team2View.Create(); team2View.Id = Guid.NewGuid(); team2View.ViewId = view.Id; team2View.TeamId = teamId; DbContext.Entry(team2View).State = EntityState.Added; } } List companiesFiltered = new List(); if (model.Companies != null) { // Filter companies: exclude child ones from list, if parent company selected companiesFiltered = this.FilterCompanyList(model.Companies.ToList(), availableCompanies); } var currentCompanies = DbContext.Company2View.Where(x => x.ViewId == view.Id).ToList(); var companiesToRemove = currentCompanies.Where(x => !companiesFiltered.Contains(x.CompanyId)); if ((model.Watchers == null) || (model.Watchers.Count != 1) || !model.Watchers.First().Equals(userId)) { // If the only watcher for this view is current user, remove all deleted records. // Otherwise, remove the only companies, current user has access to var availableCompaniesPlain = availableCompanies.Keys.ToList(); availableCompaniesPlain.AddRange(availableCompanies.Values.SelectMany(x => x)); companiesToRemove = companiesToRemove.Where(x => availableCompaniesPlain.Contains(x.CompanyId)); } companiesToRemove.ToList().ForEach(x => DbContext.Entry(x).State = EntityState.Deleted); if (companiesFiltered.Count > 0) { var exisingCompanies = currentCompanies.Select(x => x.CompanyId).ToList(); var companiesToAdd = companiesFiltered.Where(x => !exisingCompanies.Contains(x)).ToList(); foreach (var companyId in companiesToAdd) { var company2View = DbContext.Company2View.Create(); company2View.Id = Guid.NewGuid(); company2View.ViewId = view.Id; company2View.CompanyId = companyId; DbContext.Entry(company2View).State = EntityState.Added; } } #endregion } //env-753 start if (model.Teams != null && model.Watchers != null) { var users = model.Watchers.Select(x => x.ToString()); var user2teams = DbContext.User2Team.Where(x => model.Teams.Contains(x.TeamId) && users.Contains(x.UserId)).ToList(); foreach (var watcherId in model.Watchers) { foreach (var teamId in model.Teams) { if (user2teams.Any(x => x.UserId.Equals(watcherId.ToString(), StringComparison.InvariantCultureIgnoreCase) && x.TeamId == teamId)) continue; DbContext.User2Team.Add(new User2Team { Id = Guid.NewGuid(), UserId = watcherId.ToString(), TeamId = teamId }); } } } //env-753 end return view; } public ViewModel LoadWithChildCollections(Guid? value, bool isReadOnly = true) { var result = (ViewModel)base.Load(value, isReadOnly); if (result != null && value.HasValue) { var users = DbContext.User2View.Where(x => x.ViewId == value.Value).ToList(); result.Watchers = users.Select(x => x.UserId).ToList(); var teams = DbContext.Team2View.Where(t => t.ViewId == value.Value).ToList(); result.Teams = teams.Select(t => t.TeamId).ToList(); var companies = DbContext.Company2View.Where(t => t.ViewId == value.Value).ToList(); result.Companies = companies.Select(t => t.CompanyId).ToList(); } return result; } protected override View InitInstance() { return new View { Id = Guid.NewGuid() }; } protected override View RetrieveReadOnlyById(Guid key) { return DataTable.AsNoTracking().FirstOrDefault(t => t.Id == key); } public override DbSet DataTable { get { return DbContext.Views; } } public IList GetViewsByOwner(Guid? ownerId, bool skipVirtualViews = true) { IList result = null; Task> viewsTask = null; Task> companiesTask = null; if (ownerId.HasValue) { viewsTask = DbContext.User2View.Include(x => x.View).Where(x => x.UserId.Equals(ownerId.Value) && x.ViewId.HasValue) .AsNoTracking().Select(x => new ViewListModel { Id = x.ViewId.Value, Name = x.View.Name }).ToListAsync(); } else { viewsTask = Task.FromResult(new List()); } using (viewsTask) { if (!skipVirtualViews) // get all companies (parent and child) assigned to user directly (do not show virtual views for companies related to user implicitly) // Query data in separate context to avoid query's intersection companiesTask = (new CompanyManager(new EnVisageEntities())).GetCompaniesByUserAsync(ownerId); else companiesTask = Task.FromResult(new List()); using (companiesTask) { Task.WaitAll(viewsTask, companiesTask); var companyVirtualViews = companiesTask.Result.Select(x => new ViewListModel { Id = x.Id, Name = x.Name, CompanyId = x.Id }); result = viewsTask.Result.Concat(companyVirtualViews).ToList(); } } return result; } public List GetTeamsWithResourcesByUser(Guid viewId, Guid userId) { if (Guid.Empty.Equals(viewId)) return new List(); var views = new List() { viewId }; var teams = GetTeamsWithResourcesByUser(views, userId); return teams; } public List GetTeamsWithResourcesByUser(List views, Guid userId) { if (views == null || views.Count <= 0) return new List(); TeamManager teamMngr = new TeamManager(DbContext); var viewTeams = teamMngr.GetTeamsByViewsByUser(views, userId).Select(t => t.TeamId); var query = (from t in DbContext.Teams join pr in DbContext.VW_TeamResource on t.Id equals pr.TeamId into prl from p in prl.DefaultIfEmpty() join exp in DbContext.ExpenditureCategory on p.ExpenditureCategoryId equals exp.Id into egr from e in egr.DefaultIfEmpty() where viewTeams.Contains(t.Id) orderby t.Name select new { Team = t, PeopleResource = p, ExpCat = e }).AsNoTracking().Distinct(); var result = new Dictionary(); foreach (var item in query) { if (!result.ContainsKey(item.Team.Id)) { result.Add(item.Team.Id, (TeamWithResourcesModel)item.Team); } if (item.PeopleResource != null) result[item.Team.Id].PeopleResources.Add(PeopleResourceModel.GetPeopleResourceModel(item.PeopleResource, item.ExpCat, item.Team)); } var teams = result.Values.ToList(); teams.ForEach(t => t.PeopleResources = t.PeopleResources.OrderBy(r => r.FirstName + r.LastName).ToList()); return teams; } #region Private Methods private Dictionary> GetVisibleToUserCompanies(Guid userId) { CompanyManager mngr = new CompanyManager(DbContext); var visible2UserCompanies = mngr.GetCompaniesByUser(userId); var allCompaniesTree = visible2UserCompanies.Where(x => !x.ParentCompanyId.HasValue || (x.ParentCompanyId.HasValue && !visible2UserCompanies.Where(z => z.Id.Equals(x.ParentCompanyId.Value)).Any())) .ToDictionary(k => k.Id, v => visible2UserCompanies.Where(ch => ch.ParentCompanyId.HasValue && ch.ParentCompanyId.Value.Equals(v.Id)) .Select(ch => ch.Id).ToList()); return allCompaniesTree; } private List FilterCompanyList(List srcCompanies, Dictionary> visible2UserCompaniesTree) { if ((srcCompanies == null) || (srcCompanies.Count < 1)) return srcCompanies; if ((visible2UserCompaniesTree == null) || (visible2UserCompaniesTree.Count < 1)) return new List(); var result = new List(srcCompanies); foreach (var prntCompany in visible2UserCompaniesTree.Keys) { // If parent company selected, remove all child companies from the result list if (result.Contains(prntCompany)) result.RemoveAll(x => visible2UserCompaniesTree[prntCompany].Contains(x)); } return result; } #endregion } }