using EnVisage.Models; using System; using System.Collections.Generic; using System.Data.Entity; using System.Data.Entity.Validation; using System.Linq; using System.Text; using System.Web; namespace EnVisage.Code.BLL { public class NotificationManager: ManagerBase { public NotificationManager(EnVisageEntities dbContext): base(dbContext) { } protected override Notification InitInstance() { return new Notification { Id = Guid.NewGuid() }; } protected override Notification RetrieveReadOnlyById(Guid key) { return DataTable.AsNoTracking().FirstOrDefault(t => t.Id == key); } public override DbSet DataTable => DbContext.Notifications; public override Notification Save(NotificationModel model) { if (model == null) throw new ArgumentNullException(nameof(model)); bool newDbObject = false; Notification dbObj = null; if (model.Id != Guid.Empty) dbObj = DataTable.Find(model.Id); if (dbObj == null) { newDbObject = true; dbObj = new Notification { Id = model.Id }; model.Actions = GetNotificationActions(model.type); } model.CopyTo(dbObj); if (newDbObject) DbContext.Notifications.Add(dbObj); else DbContext.Entry(dbObj).State = EntityState.Modified; if (IsContextLocal) DbContext.SaveChanges(); var actions = GetNotificationActions(model.type); model.Actions = actions; Hubs.Notifications.NotificationRouter.sentNotification(model); return dbObj; } public void Delete(Guid id) { Notification dbObj = Load(id, false); NotificationModel model = new NotificationModel(dbObj, DbContext); model.Actions = GetNotificationActions(model.type); if (dbObj != null) DbContext.Notifications.Remove(dbObj); if (IsContextLocal) DbContext.SaveChanges(); Hubs.Notifications.NotificationRouter.removeNotification(model); } public Dictionary> GetNotifications(Guid parentId, NotificationGroupType? grouptype) { return GetNotifications(new List { parentId }, grouptype); } public Dictionary> GetNotifications(Guid parentId) { return GetNotifications(new List { parentId }); } public Dictionary> GetNotifications(List parentIds, NotificationGroupType? grouptype) { if (parentIds == null || parentIds.Count <= 0) return new Dictionary>(); var notificationsQuery = DbContext.Notifications.Where(x => x.ParentId.HasValue && parentIds.Contains(x.ParentId.Value)); if (grouptype.HasValue) notificationsQuery = notificationsQuery.Where(x => x.NotificationGroup == (int)grouptype); return notificationsQuery.OrderBy(x => x.NotificationDate).ToList().GroupBy(x => x.ParentId.Value) .ToDictionary(x => x.Key, g => g.ToList()); } public List GetNotifications(NotificationGroupType? type) { if (type == null) return new List(); var notificationsQuery = DbContext.Notifications.Where(x => x.NotificationGroup == (int)type); return notificationsQuery.ToList(); } public List GetNotifications(NotificationGroupType? grouptype, NotificationType? type) { if (type == null && grouptype == null) return new List(); var notificationsQuery = DbContext.Notifications.Where(x => x.NotificationGroup == (int)grouptype && x.NotificationType == (int)type).OrderBy(x => x.NotificationDate); return notificationsQuery.ToList(); } public Dictionary> GetNotifications(Guid parentId, NotificationType? type) { return GetNotifications(new List { parentId }, type); } public Dictionary> GetNotifications(List parentIds, NotificationType? type) { if (parentIds == null || parentIds.Count <= 0) return new Dictionary>(); var notificationsQuery = DbContext.Notifications.Where(x => x.ParentId.HasValue && parentIds.Contains(x.ParentId.Value)); if (type.HasValue) notificationsQuery = notificationsQuery.Where(x => x.NotificationType == (int)type); return notificationsQuery.OrderBy(x => x.NotificationDate).ToList().GroupBy(x => x.ParentId.Value) .ToDictionary(x => x.Key, g => g.ToList()); } public Dictionary> GetNotifications(List parentIds) { if (parentIds == null || parentIds.Count <= 0) return new Dictionary>(); var notificationsQuery = DbContext.Notifications.Where(x => x.ParentId.HasValue && parentIds.Contains(x.ParentId.Value) && x.NotificationViewed != true); Dictionary> dc = notificationsQuery.OrderBy(x => x.NotificationDate).ToList().GroupBy(x => x.ParentId.Value) .ToDictionary(x => x.Key, g => g.ToList()); dc = CleanOldNotifications(parentIds, dc); return dc; } public List GetNotificationActions(NotificationType type) { var notificationsQuery = DbContext.NotificationControls.Where(x => x.NotificationType == (int)type); var notificationMethod = new List(); foreach (var x in notificationsQuery) { notificationMethod.Add(new NotificationControlModel() { Id = x.Id, type = (NotificationType)x.NotificationType, HowToSend = (NotificationHowToSend)x.HowtoSend }); } return notificationMethod; } public void UpdateNotificationAsViewed(NotificationModel notification) { var n= DataTable.FirstOrDefault(x => x.Id == notification.Id); if (n != null) { n.NotificationViewed = true; DbContext.Entry(n).State = EntityState.Modified; } if (IsContextLocal) DbContext.SaveChanges(); } public void RemoveNotification(Guid userid, Guid parentId) { var notifys = GetNotificationList(userid, parentId); foreach (var n in notifys) { if (n.ExpiresOnDate == null) { DbContext.Notifications.Remove(n); DbContext.Entry(n).State = EntityState.Deleted; } } if (IsContextLocal) DbContext.SaveChanges(); } public void UpdateNotificationAsViewed(Guid userid, Guid parentId) { var notifys = GetNotificationList(userid, parentId); foreach (var n in notifys) { if (n.ExpiresOnDate == null) { n.NotificationViewed = true; DbContext.Entry(n).State = EntityState.Modified; } } if (IsContextLocal) DbContext.SaveChanges(); } private ListGetNotificationList(Guid userid, Guid parentId) { var scenarios = DbContext.Scenarios.Where(x => x.Id == parentId).ToList(); if (scenarios.Count == 0) scenarios = DbContext.Scenarios.Where(x => x.ParentId == parentId && x.Type == (int) ScenarioType.Portfolio).ToList(); var rt = new List(); var userNotifications = DbContext.Notifications.Where(x => x.ParentId == userid && !string.IsNullOrEmpty(x.Link)).ToList(); foreach (var s in scenarios) { rt.AddRange(userNotifications.Where(x => x.Link.Contains(s.Id.ToString()) || x.Link.Contains(s.ParentId.ToString())).ToList()); } return rt; } public void UpdateNotificationAsViewedOnLoad(Guid userid, Guid parentId) { var notifys = DbContext.Notifications.Where(x => x.ParentId == userid && !string.IsNullOrEmpty(x.Link) && x.Link.Contains(parentId.ToString()) && x.DeleteOnPageView == true).ToList(); foreach (var n in notifys) { n.NotificationViewed = true; DbContext.Entry(n).State = EntityState.Modified; } if (IsContextLocal) DbContext.SaveChanges(); } public List GetAllNotificationActions() { var notificationsQuery = DbContext.NotificationControls; var notificationMethod = new List(); foreach (var x in notificationsQuery) { notificationMethod.Add(new NotificationControlModel() { Id = x.Id, type = (NotificationType)x.NotificationType, HowToSend = (NotificationHowToSend)x.HowtoSend }); } return notificationMethod; } private Dictionary> CleanOldNotifications(List parentIds, Dictionary> list) { string userId = HttpContext.Current.User.Identity.GetUserId(); var aspUser = DbContext.AspNetUsers.FirstOrDefault(x => x.Id == userId); Dictionary > newlist = new Dictionary>(); if (aspUser != null) { var lastlogin = aspUser.LastLoginDate; var removeAfterDurationstr = new SystemSettingsManager(DbContext).GetSystemSettingsValue((int)SystemSettingType.RemoveNotificationsAfterDays); int removeAfterDuration = 1; if (!string.IsNullOrEmpty(removeAfterDurationstr)) Int32.TryParse(removeAfterDurationstr, out removeAfterDuration); if (removeAfterDuration < 0) removeAfterDuration = 1; foreach (Guid id in parentIds) { var nl = new List(); if (id != Guid.Empty) { //get last login date if (lastlogin != null) { if (list.ContainsKey(id)) { foreach (Notification n in list[id]) { TimeSpan diff = lastlogin.Value - n.NotificationDate; if (diff.TotalDays >= removeAfterDuration && n.NotificationViewed) Delete(n.Id); else nl.Add(n); } } } else { if (list.ContainsKey(id)) { foreach (Notification n in list[id]) { nl.Add(n); } } } } else nl = list[id]; if (nl.Count > 0) newlist.Add(id, nl); } //aspUser.LastLoginDate = DateTime.Now; //this.DbContext.SaveChanges(); } return newlist; } public void SendScenarioChangeNotifications(Scenario scenario,Type t, Status s, EntityState state, string url) { try { if ((s != null && s.Id != Guid.Empty) || (t != null && t.Id != Guid.Empty)) { var userid = HttpContext.Current.User.Identity.GetID(); var user = this.DbContext.AspNetUsers.Where(x => x.Id == userid).FirstOrDefault(); string Name = "System"; if (user != null) Name = user.FirstName + " " + user.LastName; string message = ""; string title = ""; var whos = new List(); var whot = new List(); var who = new List(); Uri uri = null; if (s != null && s.Id != Guid.Empty) { if (s.NotifyOnProjectDelete.HasValue && s.NotifyOnProjectDelete.Value && state == EntityState.Deleted) { whos = (new WorkFlowManager(null)).GetContactDetails(s.Id, WorkFlowContactNotificationType.ProjectDelete, scenario.ParentId); title = scenario.Name + " has been deleted"; message = Name + " has removed the scenario from Prevu®"; url = null; } if (s.NotifyOnProjectChange.HasValue && s.NotifyOnProjectChange.Value && state == EntityState.Modified) { whos = (new WorkFlowManager(null)).GetContactDetails(s.Id, WorkFlowContactNotificationType.ProjectUpdate, scenario.ParentId); title = scenario.Name + " has been updated"; message = Name + " has updated this scenario"; } if (s.NotifyOnProjectCreate.HasValue && s.NotifyOnProjectCreate.Value && state == EntityState.Added) { whos = (new WorkFlowManager(null)).GetContactDetails(s.Id, WorkFlowContactNotificationType.ProjectCreate, scenario.ParentId); title = scenario.Name + " has been created"; message = Name + " has created this scenario"; } } if (t != null && t.Id != Guid.Empty) { if (t.NotifyOnProjectDelete.HasValue && t.NotifyOnProjectDelete.Value && state == EntityState.Deleted) { whot = (new WorkFlowManager(null)).GetContactDetails(t.Id, WorkFlowContactNotificationType.ProjectDelete, scenario.ParentId); title = scenario.Name + " has been deleted"; message = Name + " has removed the scenario from Prevu®"; } if (t.NotifyOnProjectChange.HasValue && t.NotifyOnProjectChange.Value && state == EntityState.Modified) { whot = (new WorkFlowManager(null)).GetContactDetails(t.Id, WorkFlowContactNotificationType.ProjectUpdate, scenario.ParentId); title = scenario.Name + " has been updated"; message = Name + " has updated this scenario"; } if (t.NotifyOnProjectCreate.HasValue && t.NotifyOnProjectCreate.Value && state == EntityState.Added) { whot = (new WorkFlowManager(null)).GetContactDetails(t.Id, WorkFlowContactNotificationType.ProjectCreate, scenario.ParentId); title = scenario.Name + " has been created"; message = Name + " has created this scenario"; } } whos.AddRange(whot); foreach (var w in whos) { if (!who.Any(x => x.EmailAddress == w.EmailAddress)) who.Add(w); } if (!string.IsNullOrEmpty(url)) uri = new Uri(url); foreach (var u in who) { if (this.DbContext.Notifications.Any(x => x.Title == title && x.Description == message && x.ParentId == u.UserId && x.IdinLink == scenario.Id)) continue; NotificationModel m = new NotificationModel(); m.title = title; m.description = message; m.link = uri; m.IdinLink = scenario.Id; m.WorkFlowState = null; m.WorkFlowLinkName = scenario.Name; m.NotificationGroup = NotificationGroupType.Project; m.ParentId = u.UserId; m.Id = Guid.NewGuid(); m.NotificationViewed = false; m.ExpiresOnDate = DateTime.Now.AddDays(1); m.NotificationDate = DateTime.Now; m.type = NotificationType.User; (new NotificationManager(null)).Save(m); } } } catch (Exception dd) { LogException(dd); } } public void SendProjectChangeNotifications(Project project, Type t, Status s, EntityState state,string url) { try { if (s != null && s.Id != Guid.Empty || t != null && t.Id != Guid.Empty) { var userid = HttpContext.Current.User.Identity.GetID(); var user = DbContext.AspNetUsers.FirstOrDefault(x => x.Id == userid); string name = "System"; if (user != null) name = user.FirstName + " " + user.LastName; string message = ""; string title = ""; var whos = new List(); var whot = new List(); var who = new List(); Uri uri = null; if (s != null && s.Id != Guid.Empty) { if (s.NotifyOnProjectDelete.HasValue && s.NotifyOnProjectDelete.Value && state == EntityState.Deleted) { whos = new WorkFlowManager(null).GetContactDetails(s.Id, WorkFlowContactNotificationType.ProjectDelete, project.Id); title = project.Name + " has been deleted"; message = name + " has removed the project from Prevu®"; url = null; } if (s.NotifyOnProjectChange.HasValue && s.NotifyOnProjectChange.Value && state == EntityState.Modified) { whos = new WorkFlowManager(null).GetContactDetails(s.Id, WorkFlowContactNotificationType.ProjectUpdate, project.Id); title = project.Name + " has been updated"; message = name + " has updated this project"; } if (s.NotifyOnProjectCreate.HasValue && s.NotifyOnProjectCreate.Value && state == EntityState.Added) { whos = new WorkFlowManager(null).GetContactDetails(s.Id, WorkFlowContactNotificationType.ProjectCreate, project.Id); title = project.Name + " has been created"; message = name + " has created this project"; } } if (t != null && t.Id != Guid.Empty) { if (t.NotifyOnProjectDelete.HasValue && t.NotifyOnProjectDelete.Value && state == EntityState.Deleted) { whot = new WorkFlowManager(null).GetContactDetails(t.Id, WorkFlowContactNotificationType.ProjectDelete, project.Id); title = project.Name + " has been deleted"; message = name + " has removed the project from Prevu®"; } if (t.NotifyOnProjectChange.HasValue && t.NotifyOnProjectChange.Value && state == EntityState.Modified) { whot = new WorkFlowManager(null).GetContactDetails(t.Id, WorkFlowContactNotificationType.ProjectUpdate, project.Id); title = project.Name + " has been updated"; message = name + " has updated this project"; } if (t.NotifyOnProjectCreate.HasValue && t.NotifyOnProjectCreate.Value && state == EntityState.Added) { whot = (new WorkFlowManager(null)).GetContactDetails(t.Id, WorkFlowContactNotificationType.ProjectCreate, project.Id); title = project.Name + " has been created"; message = name + " has created this project"; } } whos.AddRange(whot); foreach (var w in whos) { if (who.All(x => x.EmailAddress != w.EmailAddress)) who.Add(w); } if (!string.IsNullOrEmpty(url)) uri = new Uri(url); foreach (var u in who) { if (DbContext.Notifications.Any(x => x.Title == title && x.Description == message && x.ParentId == u.UserId && x.IdinLink == project.Id)) continue; NotificationModel m = new NotificationModel { title = title, description = message, link = uri, IdinLink = project.Id, WorkFlowState = null, WorkFlowLinkName = project.Name, NotificationGroup = NotificationGroupType.Project, ParentId = u.UserId, Id = Guid.NewGuid(), NotificationViewed = false, ExpiresOnDate = DateTime.Now.AddDays(1), NotificationDate = DateTime.Now, type = NotificationType.User }; (new NotificationManager(null)).Save(m); } } }catch (Exception dd) { LogException(dd); } } public void ClearExpiredNotifications() { var ids= DataTable.Where(x => x.ExpiresOnDate <= DateTime.Now).Select(x=>x.Id).ToList(); foreach (var id in ids) Delete(id); } public void CreateTeamAddNotification(List who,Guid id, int expiresOnDays, bool expireOnView, string wfstate) { try { if (id == Guid.Empty) return; string title_tmplt = "Your team has been added to {ProjectName}"; string message_tmplt = "{ProjectName} requires your attention"; var projectId = DbContext.Scenarios.Where(x => x.Id == id).Select(x => x.ParentId).FirstOrDefault(); bool sendToProject = false; string linkName = "Scenario"; Guid idInLink = id; if (projectId == null || projectId == Guid.Empty) { projectId = id; sendToProject = true; linkName = "Project"; } string projectName = DbContext.Projects.Where(x => x.Id == projectId).Select(x => x.Name).FirstOrDefault(); var url = sendToProject ? Session.AbsoluteUrl.EditProjectUrl(projectId, DbContext) : Session.AbsoluteUrl.EditScenarioUrl(id, DbContext); Uri uri = null; if (!string.IsNullOrEmpty(url)) uri = new Uri(url); DateTime? expiresOnDate = null; if (expiresOnDays > 0) expiresOnDate = DateTime.Now.AddDays(expiresOnDays); foreach (var u in who) { var title = title_tmplt.Replace("{TeamName}", u.TeamName).Replace("{ProjectName}", projectName); var message = message_tmplt.Replace("{ProjectName}", projectName); if (DbContext.Notifications.Any(x => x.Title == title && x.Description == message && x.ParentId == u.UserId && x.IdinLink == projectId && x.NotificationViewed ==false)) continue; NotificationModel m = new NotificationModel { title = title, description = message, link = uri, ExpiresOnDate = expiresOnDate, IdinLink = idInLink, WorkFlowState = wfstate, WorkFlowLinkName = linkName, NotificationGroup = NotificationGroupType.Project, ParentId = u.UserId, Id = Guid.NewGuid(), NotificationViewed = false, DeleteOnPageView = expireOnView, NotificationDate = DateTime.Now, type = NotificationType.User }; (new NotificationManager(null)).Save(m); } }catch(Exception dd) { LogException(dd); } } private void LogException(Exception ex) { var sb = new StringBuilder(); sb.AppendLine($"{ex.GetType()}: {ex.Message}"); sb.AppendLine(ex.StackTrace); var innerCount = 0; var innerEx = ex; while (innerEx.InnerException != null && innerCount++ < Constants.MAX_INNER_EXCEPTION_LOG_LEVEL) { if (innerEx.Message != innerEx.InnerException.Message) sb.AppendLine("Inner Exception Message: " + innerEx.InnerException.Message); innerEx = innerEx.InnerException; } var dbEntityValidationException = ex as DbEntityValidationException; if (dbEntityValidationException != null) { foreach (var validationErrors in dbEntityValidationException.EntityValidationErrors) { foreach (var validationError in validationErrors.ValidationErrors) { sb.AppendFormat("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage); } } sb.AppendLine(dbEntityValidationException.StackTrace); } if (HttpContext.Current != null) { sb.AppendLine(); sb.AppendLine($"URL: {HttpContext.Current.Request.Url}"); sb.AppendLine($"Referrer: {HttpContext.Current.Request.UrlReferrer}"); sb.AppendLine($"QueryString: {HttpContext.Current.Request.QueryString}"); sb.AppendLine($"UserHostAddress: {HttpContext.Current.Request.UserHostAddress}"); sb.AppendLine($"UserAgent: {HttpContext.Current.Request.UserAgent}"); if (HttpContext.Current.Request.Form.Count > 0) { sb.AppendLine(); sb.AppendLine("Form:"); foreach (string key in HttpContext.Current.Request.Form.Keys) { sb.AppendLine($"{key}: {HttpContext.Current.Request.Form[key]}"); } } } // log error using NLog Logger.Fatal(sb.ToString()); } } }