Example #1
0
        private void ProcessWatchers(List <IssueDto> issues, DateTime lastChecked)
        {
            var lastCheckedLocal = lastChecked.ToLocal(_issueManager.UserContext.User.TimeZone);

            Dictionary <int, WatcherData>    targets      = new Dictionary <int, WatcherData>();
            Dictionary <string, WatcherData> emailTargets = new Dictionary <string, WatcherData>();
            var        userManager = new UserManager(_issueManager);
            List <int> projectsMissingFollowerTemplate = new List <int>();
            int        emailWatchers = -3;

            LogDebugMessage(string.Concat("Processing follower - ", issues.Count, " items found"));
            // Build array of users that are watching issues
            foreach (var issue in issues)
            {
                //Safety check
                if (issue.Watchers.Count == 0)
                {
                    continue;
                }
                if (issue.Revised == issue.Created)
                {
                    continue;
                }
                if (issue.Revised.ToUtc(_issueManager.UserContext.User.TimeZone) <= lastChecked)
                {
                    continue;
                }

                var history = _issueManager.GetHistory(issue);

                issue.History = new List <IssueAuditDto>(history);

                history.RemoveAll(h => h.Entity.Created <= lastCheckedLocal);

                foreach (var watcher in issue.Watchers)
                {
                    if (watcher.Entity.UserId != null)
                    {
                        if (targets.ContainsKey(watcher.Entity.UserId.Value))
                        {
                            WatcherData data = targets[watcher.Entity.UserId.Value];

                            var permissionManager = new PermissionsManager(data.User, _types, _permissionSets, _organizations, _issueManager.UserContext.Config.HelpDeskModeGroup, false);

                            if (!permissionManager.CanSeeItem(issue.Project, issue))
                            {
                                continue;
                            }

                            if (!data.User.Entity.EmailMeMyChanges && IsUserOnlyChange(history, data.User.Entity.Id))
                            {
                                continue;
                            }

                            data.IssueId.Add(issue.Entity.Id);
                        }
                        else
                        {
                            WatcherData data = new WatcherData();

                            data.User = userManager.Get(watcher.Entity.UserId.Value);

                            if (data.User.Entity.Active)
                            {
                                var permissionManager = new PermissionsManager(data.User, _types, _permissionSets, _organizations, _issueManager.UserContext.Config.HelpDeskModeGroup, false);

                                if (!permissionManager.CanSeeItem(issue.Project, issue))
                                {
                                    continue;
                                }

                                if (!data.User.Entity.EmailMeMyChanges && IsUserOnlyChange(history, data.User.Entity.Id))
                                {
                                    continue;
                                }

                                data.IssueId.Add(issue.Entity.Id);

                                targets.Add(watcher.Entity.UserId.Value, data);
                            }
                        }
                    }
                    else
                    {
                        if (emailTargets.ContainsKey(watcher.Entity.Email.ToLower()))
                        {
                            WatcherData data = emailTargets[watcher.Entity.Email.ToLower()];
                            data = targets[data.User.Entity.Id];
                            data.IssueId.Add(issue.Entity.Id);
                        }
                        else
                        {
                            WatcherData data = new WatcherData();
                            data.User                         = new UserDto(new User());
                            data.User.Entity.Id               = emailWatchers--;
                            data.User.Entity.Email            = watcher.Entity.Email;
                            data.User.Entity.EmailMe          = true;
                            data.User.Entity.EmailMeMyChanges = true;
                            data.User.Entity.ProjectGroups.Add(new ProjectGroupMembership()
                            {
                                ProjectGroupId = Constants.GlobalGroupEveryone, UserId = data.User.Entity.Id
                            });
                            UserSettings settings = new UserSettings();
                            settings.IndividualFollowerAlerts = true;
                            data.User.Entity.Settings         = settings.ToJson();
                            var group = new ProjectGroup()
                            {
                                Id = Constants.GlobalGroupEveryone, Members = new List <ProjectGroupMembership>()
                            };
                            group.Members2.Add(new ProjectGroupMembership()
                            {
                                UserId = data.User.Entity.Id, ProjectGroupId = Constants.GlobalGroupEveryone
                            });
                            data.User.ProjectGroups.Add(group);
                            data.IssueId.Add(issue.Entity.Id);
                            emailTargets.Add(watcher.Entity.Email.ToLower(), data);
                            targets.Add(data.User.Entity.Id, data);
                        }
                    }
                }
            }
            var langMan = new LanguageManager(_issueManager);
            AlertsTemplateHelper alerts = new AlertsTemplateHelper(_templates, GetUrl(_issueManager), _languages);

            // Now loop through users sending them watcher summary email
            Dictionary <int, List <IssueCommentDto> > originalComments = new Dictionary <int, List <IssueCommentDto> >();
            List <int> processedProjects;

            foreach (var target in targets)
            {
                processedProjects = new List <int>();

                if (originalComments.Count > 0)
                {
                    foreach (var kv in originalComments)
                    {
                        IssueDto issue = issues.Find(i => i.Entity.Id == kv.Key);

                        // Safety check
                        if (issue == null || issue.Entity.IsNew)
                        {
                            continue;
                        }

                        issue.Comments = kv.Value;
                    }

                    originalComments = new Dictionary <int, List <IssueCommentDto> >();
                }

                var recipient = target.Value;

                // Safety check
                if (!recipient.User.Entity.EmailMe || recipient.User.Entity.Email.IsEmpty())
                {
                    continue;
                }

                AlertTypeWatchersTemplateModel model = new AlertTypeWatchersTemplateModel();

                model.TheRecipient = recipient.User;

                model.Version = GeminiVersion.Version;

                model.GeminiUrl = alerts.GeminiUrl;

                foreach (int issueId in recipient.IssueId)
                {
                    IssueDto issue = issues.Find(i => i.Entity.Id == issueId);

                    // Safety check
                    if (issue == null || issue.Entity.IsNew)
                    {
                        continue;
                    }

                    issue.ChangeLog = _issueManager.GetChangeLog(issue, _issueManager.UserContext.User, recipient.User, lastCheckedLocal);

                    var permissionManager = new PermissionsManager(recipient.User, _types, _permissionSets, _organizations, _issueManager.UserContext.Config.HelpDeskModeGroup, false);

                    foreach (var comment in issue.Comments)
                    {
                        if (!permissionManager.CanSeeComment(issue, comment))
                        {
                            originalComments.Add(issueId, issue.Comments);

                            List <IssueCommentDto> comments = new List <IssueCommentDto>(issue.Comments);

                            comments.RemoveAll(c => !permissionManager.CanSeeComment(issue, c));

                            issue.Comments = comments;

                            break;
                        }
                    }

                    if (issue.ChangeLog.Count == 0)
                    {
                        continue;
                    }

                    if (recipient.User.GetSettings().IndividualFollowerAlerts)
                    {
                        var template = alerts.FindTemplateForProject(AlertTemplateType.Updated,
                                                                     issue.Entity.ProjectId, GetLanguageId(recipient.User));

                        if (template == null)
                        {
                            LogDebugMessage("No update notification template found");
                            continue;
                        }

                        var indModel = new AlertTypeIndividualTemplateModel();

                        indModel.GeminiUrl = model.GeminiUrl;

                        indModel.LinkViewItem = NavigationHelper.GetIssueUrl(_issueManager.UserContext, issue.Entity.ProjectId, issue.EscapedProjectCode, issue.Entity.Id);

                        indModel.TheItem = issue;

                        indModel.TheRecipient = recipient.User;

                        indModel.Version = GeminiVersion.Version;

                        indModel.IsNewItem = false;

                        string html = alerts.GenerateHtml(template, indModel);

                        if (GeminiApp.GeminiLicense.IsFree)
                        {
                            html = alerts.AddSignature(html);
                        }

                        string log;

                        string subject = template.Options.Subject.HasValue() ? alerts.GenerateHtml(template, indModel, true) : string.Format("[{0}] {1} {2} ({3})", issue.IssueKey, issue.Type, "Updated", issue.Title, issue.IsClosed ? "Closed" : string.Empty);
                        LogDebugMessage(string.Concat("Processing follower - Send item ", issue.IssueKey, " to ", recipient.User.Entity.Email));
                        EmailHelper.Send(_issueManager.UserContext.Config, subject, html, recipient.User.Entity.Email, recipient.User.Fullname, true, out log);
                    }
                    else
                    {
                        model.TheItemsUpdated.Add(issue);
                    }
                }

                if (recipient.User.GetSettings().IndividualFollowerAlerts)
                {
                    continue;
                }

                // Safety check!
                if (model.ChangeCount > 0)
                {
                    var watcherAlertTemplates = alerts.Templates.FindAll(s => s.AlertType == AlertTemplateType.Watchers);

                    if (watcherAlertTemplates.Count == 0)
                    {
                        LogDebugMessage("No follower notification template found");
                        continue;
                    }

                    if (!watcherAlertTemplates.Any(p => p.GetAssociatedProjectValue().IsEmpty()))
                    {
                        List <Project> allItemProjects = model.TheItemsUpdated.Select(s => s.Project).ToList();
                        allItemProjects = allItemProjects.Where(s => !watcherAlertTemplates.Any(a => a.GetAssociatedProjects().Contains(s.Id))).ToList();

                        if (projectsMissingFollowerTemplate.Count > 0)
                        {
                            allItemProjects = allItemProjects.Where(s => !projectsMissingFollowerTemplate.Contains(s.Id)).ToList();
                        }

                        if (allItemProjects.Count > 0)
                        {
                            LogDebugMessage(string.Concat("No follower notification template found for project ", string.Join(", ", allItemProjects.Select(s => s.Name).Distinct())));
                            projectsMissingFollowerTemplate.AddRange(allItemProjects.Select(s => s.Id).Distinct());
                        }
                    }

                    watcherAlertTemplates.Sort((x, y) => y.GetAssociatedProjectValue().CompareTo(x.GetAssociatedProjectValue()));

                    foreach (var watcherTemplate in watcherAlertTemplates)
                    {
                        var allTemplateProjects = watcherTemplate.GetAssociatedProjects();

                        var issuesTemplate = allTemplateProjects.Count == 0 ? model.TheItemsUpdated : model.TheItemsUpdated.FindAll(s => allTemplateProjects.Contains(s.Entity.ProjectId));

                        if (issuesTemplate.Count == 0)
                        {
                            continue;
                        }

                        var projectIds = issuesTemplate.Select(s => s.Entity.ProjectId).Distinct();

                        if (processedProjects.Count > 0)
                        {
                            projectIds     = projectIds.Where(s => !processedProjects.Contains(s));
                            issuesTemplate = issuesTemplate.Where(s => !processedProjects.Contains(s.Entity.ProjectId)).ToList();
                        }

                        if (processedProjects.Contains(0) || projectIds.Count() == 0 || issuesTemplate.Count == 0)
                        {
                            continue;
                        }

                        AlertTypeWatchersTemplateModel projectTemplateModel = new AlertTypeWatchersTemplateModel();

                        projectTemplateModel.TheItemsUpdated.AddRange(issuesTemplate);
                        projectTemplateModel.TheRecipient = model.TheRecipient;
                        projectTemplateModel.Version      = model.Version;
                        projectTemplateModel.GeminiUrl    = model.GeminiUrl;

                        AlertTemplate template = alerts.FindTemplateForProject(AlertTemplateType.Watchers,
                                                                               issuesTemplate.First().Entity.ProjectId, GetLanguageId(model.TheRecipient));

                        if (template.Id == 0)
                        {
                            continue;
                        }

                        // Generate email template
                        string html = alerts.GenerateHtml(template, projectTemplateModel);

                        if (GeminiApp.GeminiLicense.IsFree)
                        {
                            html = alerts.AddSignature(html);
                        }

                        string subject = template.Options.Subject.HasValue() ? alerts.GenerateHtml(template, projectTemplateModel, true) : string.Format("{0} {1}", projectTemplateModel.ChangeCount, "Gemini Updates");

                        // Send email
                        string log;
                        LogDebugMessage(string.Concat("Processing follower - Send items ", issuesTemplate.Select(i => i.IssueKey).ToDelimited(", "), " to ", recipient.User.Entity.Email));
                        EmailHelper.Send(_issueManager.UserContext.Config, subject, html, recipient.User.Entity.Email, recipient.User.Entity.Fullname, true, out log);

                        if (allTemplateProjects.Count == 0)
                        {
                            processedProjects.Add(0);
                        }
                        else
                        {
                            processedProjects.AddRange(projectIds);
                        }
                    }
                }
            }
        }
        private void ProcessWatchers(List<IssueDto> issues, DateTime lastChecked)
        {
            var lastCheckedLocal = lastChecked.ToLocal(_issueManager.UserContext.User.TimeZone);

            Dictionary<int, WatcherData> targets = new Dictionary<int, WatcherData>();
            Dictionary<string, WatcherData> emailTargets = new Dictionary<string, WatcherData>();
            var userManager = new UserManager(_issueManager);
            List<int> projectsMissingFollowerTemplate = new List<int>();
            int emailWatchers = -3;

            // Build array of users that are watching issues
            foreach (var issue in issues)
            {
                //Safety check
                if (issue.Watchers.Count == 0) continue;
                if (issue.Revised == issue.Created) continue;
                if (issue.Revised.ToUtc(_issueManager.UserContext.User.TimeZone) <= lastChecked) continue;

                var history = _issueManager.GetHistory(issue);

                issue.History = new List<IssueAuditDto>(history);

                history.RemoveAll(h => h.Entity.Created <= lastCheckedLocal);

                foreach (var watcher in issue.Watchers)
                {
                    if (watcher.Entity.UserId != null)
                    {
                        if (targets.ContainsKey(watcher.Entity.UserId.Value))
                        {
                            WatcherData data = targets[watcher.Entity.UserId.Value];

                            var permissionManager = new PermissionsManager(data.User, _types, _permissionSets, _organizations, _issueManager.UserContext.Config.HelpDeskModeGroup, false);

                            if (!permissionManager.CanSeeItem(issue.Project, issue)) continue;

                            if (!data.User.Entity.EmailMeMyChanges && IsUserOnlyChange(history, data.User.Entity.Id)) continue;

                            data.IssueId.Add(issue.Entity.Id);
                        }
                        else
                        {
                            WatcherData data = new WatcherData();

                            data.User = userManager.Get(watcher.Entity.UserId.Value);

                            if (data.User.Entity.Active)
                            {
                                var permissionManager = new PermissionsManager(data.User, _types, _permissionSets, _organizations, _issueManager.UserContext.Config.HelpDeskModeGroup, false);

                                if (!permissionManager.CanSeeItem(issue.Project, issue)) continue;

                                if (!data.User.Entity.EmailMeMyChanges && IsUserOnlyChange(history, data.User.Entity.Id)) continue;

                                data.IssueId.Add(issue.Entity.Id);

                                targets.Add(watcher.Entity.UserId.Value, data);
                            }
                        }
                    }
                    else
                    {
                        if (emailTargets.ContainsKey(watcher.Entity.Email.ToLower()))
                        {
                            WatcherData data = emailTargets[watcher.Entity.Email.ToLower()];
                            data = targets[data.User.Entity.Id];
                            data.IssueId.Add(issue.Entity.Id);
                        }
                        else
                        {
                            WatcherData data = new WatcherData();
                            data.User = new UserDto(new User());
                            data.User.Entity.Id = emailWatchers--;
                            data.User.Entity.Email = watcher.Entity.Email;
                            data.User.Entity.EmailMe = true;
                            data.User.Entity.EmailMeMyChanges = true;
                            data.User.Entity.ProjectGroups.Add(new ProjectGroupMembership() { ProjectGroupId = Constants.GlobalGroupEveryone, UserId = data.User.Entity.Id });
                            UserSettings settings = new UserSettings();
                            settings.IndividualFollowerAlerts = true;
                            data.User.Entity.Settings = settings.ToJson();
                            var group = new ProjectGroup() { Id = Constants.GlobalGroupEveryone, Members = new List<ProjectGroupMembership>() };
                            group.Members2.Add(new ProjectGroupMembership() { UserId = data.User.Entity.Id, ProjectGroupId = Constants.GlobalGroupEveryone });
                            data.User.ProjectGroups.Add(group);
                            data.IssueId.Add(issue.Entity.Id);
                            emailTargets.Add(watcher.Entity.Email.ToLower(), data);
                            targets.Add(data.User.Entity.Id, data);
                        }
                    }
                }
            }

            AlertsTemplateHelper alerts = new AlertsTemplateHelper(_templates, GetUrl(_issueManager));

            // Now loop through users sending them watcher summary email
            Dictionary<int, List<IssueCommentDto>> originalComments = new Dictionary<int, List<IssueCommentDto>>();
            List<int> processedProjects;

            foreach (var target in targets)
            {
                processedProjects = new List<int>();

                if (originalComments.Count > 0)
                {
                    foreach (var kv in originalComments)
                    {
                        IssueDto issue = issues.Find(i => i.Entity.Id == kv.Key);

                        // Safety check
                        if (issue == null || issue.Entity.IsNew) continue;

                        issue.Comments = kv.Value;
                    }

                    originalComments = new Dictionary<int, List<IssueCommentDto>>();
                }

                var recipient = target.Value;

                // Safety check
                if (!recipient.User.Entity.EmailMe || recipient.User.Entity.Email.IsEmpty()) continue;

                AlertTypeWatchersTemplateModel model = new AlertTypeWatchersTemplateModel();

                model.TheRecipient = recipient.User;

                model.Version = GeminiVersion.Version;

                model.GeminiUrl = alerts.GeminiUrl;

                foreach (int issueId in recipient.IssueId)
                {
                    IssueDto issue = issues.Find(i => i.Entity.Id == issueId);

                    // Safety check
                    if (issue == null || issue.Entity.IsNew) continue;

                    issue.ChangeLog = _issueManager.GetChangeLog(issue, _issueManager.UserContext.User, recipient.User, lastCheckedLocal);

                    var permissionManager = new PermissionsManager(recipient.User, _types, _permissionSets, _organizations, _issueManager.UserContext.Config.HelpDeskModeGroup, false);

                    foreach (var comment in issue.Comments)
                    {
                        if (!permissionManager.CanSeeComment(issue, comment))
                        {
                            originalComments.Add(issueId, issue.Comments);

                            List<IssueCommentDto> comments = new List<IssueCommentDto>(issue.Comments);

                            comments.RemoveAll(c => !permissionManager.CanSeeComment(issue, c));

                            issue.Comments = comments;

                            break;
                        }
                    }

                    if (issue.ChangeLog.Count == 0) continue;

                    if (recipient.User.GetSettings().IndividualFollowerAlerts)
                    {
                        var template = alerts.FindTemplateForProject(AlertTemplateType.Updated, issue.Entity.ProjectId);

                        if (template == null)
                        {
                            LogDebugMessage("No update notification template found");
                            continue;
                        }

                        var indModel = new AlertTypeIndividualTemplateModel();

                        indModel.GeminiUrl = model.GeminiUrl;

                        indModel.LinkViewItem = NavigationHelper.GetIssueUrl(_issueManager.UserContext, issue.Entity.ProjectId, issue.EscapedProjectCode, issue.Entity.Id);

                        indModel.TheItem = issue;

                        indModel.TheRecipient = recipient.User;

                        indModel.Version = GeminiVersion.Version;

                        indModel.IsNewItem = false;

                        string html = alerts.GenerateHtml(template, indModel);

                        if (GeminiApp.GeminiLicense.IsFree) html = alerts.AddSignature(html);

                        string log;

                        string subject = template.Options.Subject.HasValue() ? alerts.GenerateHtml(template, indModel, true) : string.Format("[{0}] {1} {2} ({3})", issue.IssueKey, issue.Type, "Updated", issue.Title, issue.IsClosed ? "Closed" : string.Empty);

                        EmailHelper.Send(_issueManager.UserContext.Config, subject, html, recipient.User.Entity.Email, recipient.User.Fullname, true, out log);
                    }
                    else
                    {
                        model.TheItemsUpdated.Add(issue);
                    }

                }

                if (recipient.User.GetSettings().IndividualFollowerAlerts) continue;

                // Safety check!
                if (model.ChangeCount > 0)
                {
                    var watcherAlertTemplates = alerts.Templates.FindAll(s => s.AlertType == AlertTemplateType.Watchers);

                    if (watcherAlertTemplates.Count == 0)
                    {
                        LogDebugMessage("No follower notification template found");
                        continue;
                    }

                    if (!watcherAlertTemplates.Any(p => p.GetAssociatedProjectValue().IsEmpty()))
                    {
                        List<Project> allItemProjects = model.TheItemsUpdated.Select(s => s.Project).ToList();
                        allItemProjects = allItemProjects.Where(s => !watcherAlertTemplates.Any(a => a.GetAssociatedProjects().Contains(s.Id))).ToList();

                        if (projectsMissingFollowerTemplate.Count > 0)
                        {
                            allItemProjects = allItemProjects.Where(s => !projectsMissingFollowerTemplate.Contains(s.Id)).ToList();
                        }

                        if (allItemProjects.Count > 0)
                        {
                            LogDebugMessage(string.Concat("No follower notification template found for project ", string.Join(", ", allItemProjects.Select(s => s.Name).Distinct())));
                            projectsMissingFollowerTemplate.AddRange(allItemProjects.Select(s => s.Id).Distinct());
                        }
                    }

                    watcherAlertTemplates.Sort((x, y) => y.GetAssociatedProjectValue().CompareTo(x.GetAssociatedProjectValue()));

                    foreach(var watcherTemplate in watcherAlertTemplates)
                    {
                        var allTemplateProjects = watcherTemplate.GetAssociatedProjects();

                        var issuesTemplate = allTemplateProjects.Count == 0 ? model.TheItemsUpdated : model.TheItemsUpdated.FindAll(s => allTemplateProjects.Contains(s.Entity.ProjectId));

                        if (issuesTemplate.Count == 0) continue;

                        var projectIds = issuesTemplate.Select(s => s.Entity.ProjectId).Distinct();

                        if (processedProjects.Count > 0)
                        {
                            projectIds = projectIds.Where(s => !processedProjects.Contains(s));
                            issuesTemplate = issuesTemplate.Where(s => !processedProjects.Contains(s.Entity.ProjectId)).ToList();
                        }

                        if (processedProjects.Contains(0) || projectIds.Count() == 0 || issuesTemplate.Count == 0) continue;

                        AlertTypeWatchersTemplateModel projectTemplateModel = new AlertTypeWatchersTemplateModel();

                        projectTemplateModel.TheItemsUpdated.AddRange(issuesTemplate);
                        projectTemplateModel.TheRecipient = model.TheRecipient;
                        projectTemplateModel.Version = model.Version;
                        projectTemplateModel.GeminiUrl = model.GeminiUrl;

                        AlertTemplate template = alerts.FindTemplateForProject(AlertTemplateType.Watchers, issuesTemplate.First().Entity.ProjectId);

                        if (template.Id == 0)
                        {

                            continue;
                        }

                        // Generate email template
                        string html = alerts.GenerateHtml(template, projectTemplateModel);

                        if (GeminiApp.GeminiLicense.IsFree) html = alerts.AddSignature(html);

                        string subject = template.Options.Subject.HasValue() ? alerts.GenerateHtml(template, projectTemplateModel, true) : string.Format("{0} {1}", projectTemplateModel.ChangeCount, "Gemini Updates");

                        // Send email
                        string log;

                        EmailHelper.Send(_issueManager.UserContext.Config, subject, html, recipient.User.Entity.Email, recipient.User.Entity.Fullname, true, out log);

                        if (allTemplateProjects.Count == 0)
                        {
                            processedProjects.Add(0);
                        }
                        else
                        {
                            processedProjects.AddRange(projectIds);
                        }
                    }
                }
            }
        }