/// <summary> /// Sends the note approval notifications. /// </summary> /// <param name="context">The context.</param> private List <string> SendNoteApprovalNotifications(IJobExecutionContext context) { var errors = new List <string>(); List <int> noteIdsToProcessApprovalsList = new List <int>(); using (var rockContext = new RockContext()) { var noteService = new Rock.Model.NoteService(rockContext); // get all notes that are pending approval and haven't sent approval notifications yet var notesThatNeedApprovalNotifyQuery = noteService.Queryable().Where(a => a.NoteType.RequiresApprovals && a.NoteType.SendApprovalNotifications && a.ApprovalsSent == false && a.ApprovalStatus == NoteApprovalStatus.PendingApproval && a.EditedDateTime > _cutoffNoteEditDateTime); if (!notesThatNeedApprovalNotifyQuery.Any()) { // there aren't any notes that haven't had approval notifications processed yet return(errors); } noteIdsToProcessApprovalsList = notesThatNeedApprovalNotifyQuery.Select(a => a.Id).ToList(); } using (var rockContext = new RockContext()) { // get the approvers for each notetypeId Dictionary <int, List <Person> > noteTypeApprovers = new Dictionary <int, List <Person> >(); NoteTypeService noteTypeService = new NoteTypeService(rockContext); var noteTypeIdsForNotes = new NoteService(rockContext).Queryable() .Where(a => noteIdsToProcessApprovalsList.Contains(a.Id)).Select(a => a.NoteTypeId).Distinct().ToList(); foreach (var noteTypeId in noteTypeIdsForNotes) { var approvers = noteTypeService.GetApprovers(noteTypeId).ToList(); noteTypeApprovers.Add(noteTypeId, approvers); } // make a list of notes for each approver so we can send a digest of notes to approve to each approver Dictionary <Person, List <Note> > approverNotesToApproveList = new Dictionary <Person, List <Note> >(); foreach (var noteId in noteIdsToProcessApprovalsList) { var noteService = new Rock.Model.NoteService(rockContext); var note = noteService.Get(noteId); var approversForNote = noteTypeApprovers.GetValueOrNull(note.NoteTypeId); if (approversForNote?.Any() == true) { List <Note> notesToApprove; foreach (Person approverPerson in approversForNote) { if (approverNotesToApproveList.ContainsKey(approverPerson)) { notesToApprove = approverNotesToApproveList[approverPerson] ?? new List <Note>(); } else { notesToApprove = new List <Note>(); approverNotesToApproveList.Add(approverPerson, notesToApprove); } notesToApprove.Add(note); } } else { // if there are no approvers for this note type, leave it as pending approval } } if (!approverNotesToApproveList.Any()) { // nothing to do so exit return(errors); } // send approval emails var recipients = new List <RecipientData>(); foreach (var approverNotesToApprove in approverNotesToApproveList) { Person approverPerson = approverNotesToApprove.Key; List <Note> noteList = approverNotesToApprove.Value; if (!string.IsNullOrEmpty(approverPerson.Email) && approverPerson.IsEmailActive && noteList.Any()) { var mergeFields = new Dictionary <string, object>(_defaultMergeFields); mergeFields.Add("ApproverPerson", approverPerson); mergeFields.Add("NoteList", noteList); recipients.Add(new RecipientData(approverPerson.Email, mergeFields)); } if (_noteApprovalNotificationEmailGuid.HasValue) { var emailMessage = new RockEmailMessage(_noteApprovalNotificationEmailGuid.Value); emailMessage.SetRecipients(recipients); emailMessage.Send(out errors); _noteApprovalNotificationsSent += recipients.Count(); using (var rockUpdateContext = new RockContext()) { var noteListIds = noteList.Select(a => a.Id).ToList(); var notesToMarkApprovalSent = new NoteService(rockUpdateContext).Queryable().Where(a => noteListIds.Contains(a.Id)); // use BulkUpdate to mark all the notes that we processed to ApprovalsSent = true rockUpdateContext.BulkUpdate(notesToMarkApprovalSent, n => new Note { ApprovalsSent = true }); } } } } return(errors); }
/// <summary> /// Updates the note watch notification digest. /// </summary> /// <param name="personIdNotificationDigestList">The person identifier notification digest list.</param> /// <param name="rockContext">The rock context.</param> /// <param name="noteId">The note identifier.</param> private void UpdateNoteWatchNotificationDigest(Dictionary <int, NoteWatchPersonToNotifyList> personIdNotificationDigestList, RockContext rockContext, int noteId) { var noteService = new Rock.Model.NoteService(rockContext); var note = noteService.Queryable().Include(a => a.EditedByPersonAlias).FirstOrDefault(a => a.Id == noteId); if (note == null || !note.EntityId.HasValue) { // shouldn't' happen return; } var noteType = NoteTypeCache.Get(note.NoteTypeId); // make sure the note's notetype has an EntityTypeId (is should, but just in case it doesn't) int?noteEntityTypeId = noteType?.EntityTypeId; if (!noteEntityTypeId.HasValue) { return; } var noteWatchService = new Rock.Model.NoteWatchService(rockContext); // narrow it down to NoteWatches for the same EntityType as the Note var noteWatchesQuery = noteWatchService.Queryable() .Where(a => (a.EntityTypeId.HasValue && a.EntityTypeId.Value == noteEntityTypeId.Value) || (a.NoteTypeId.HasValue && a.NoteType.EntityTypeId == noteEntityTypeId)); // narrow it down to either note watches on.. // 1) specific Entity // 2) specific Note // 3) any note of the NoteType // 4) any note on the EntityType // specific Entity noteWatchesQuery = noteWatchesQuery.Where(a => (a.EntityId == null) || (note.EntityId.HasValue && a.EntityId.Value == note.EntityId.Value)); // or specifically for this Note's ParentNote (a reply to the Note) noteWatchesQuery = noteWatchesQuery.Where(a => (a.NoteId == null) || (note.ParentNoteId.HasValue && a.NoteId.Value == note.ParentNoteId)); // or specifically for this note's note type noteWatchesQuery = noteWatchesQuery.Where(a => (a.NoteTypeId == null) || (a.NoteTypeId.Value == note.NoteTypeId)); // if there are any NoteWatches that relate to this note, process them if (noteWatchesQuery.Any()) { var noteWatchesForNote = noteWatchesQuery.Include(a => a.WatcherPersonAlias.Person).AsNoTracking().ToList(); List <NoteWatchPersonToNotify> noteWatchPersonToNotifyListAll = new List <NoteWatchPersonToNotify>(); // loop thru Watches to get a list of people to possibly notify/override foreach (var noteWatch in noteWatchesForNote) { // if a specific person is the watcher, add them var watcherPerson = noteWatch.WatcherPersonAlias?.Person; if (watcherPerson != null) { // Since this is iterated do not add the person to the list if they are already there. var exists = noteWatchPersonToNotifyListAll.Where(p => p.Person.Email.Contains(watcherPerson.Email)).Any(); if (!exists) { noteWatchPersonToNotifyListAll.Add(new NoteWatchPersonToNotify(watcherPerson, note, noteWatch)); } } if (noteWatch.WatcherGroupId.HasValue) { var watcherPersonsFromGroup = new GroupMemberService(rockContext).Queryable() .Where(a => a.GroupMemberStatus == GroupMemberStatus.Active && a.GroupId == noteWatch.WatcherGroupId.Value) .Select(a => a.Person).ToList(); if (watcherPersonsFromGroup.Any()) { // Do not add people from the group that are already added. var distinctWatchers = watcherPersonsFromGroup.Where(wg => !noteWatchPersonToNotifyListAll.Where(w => w.Person.Email.Contains(wg.Email)).Any()); noteWatchPersonToNotifyListAll.AddRange(distinctWatchers.Select(a => new NoteWatchPersonToNotify(a, note, noteWatch))); } } } var noteWatchPersonToNotifyList = noteWatchPersonToNotifyListAll.Where(a => a.NoteWatch.IsWatching).ToList(); var noteWatchPersonToNotifyListWatchDisabled = noteWatchPersonToNotifyListAll.Where(a => !a.NoteWatch.IsWatching).ToList(); var noteWatchPersonToNotifyListNoOverride = noteWatchPersonToNotifyList.Where(a => a.NoteWatch.AllowOverride == false).ToList(); foreach (var noteWatchPersonToNotify in noteWatchPersonToNotifyList) { // check if somebody wanted to specifically NOT watch this (and there isn't another watch that prevents overrides) if (noteWatchPersonToNotifyListWatchDisabled.Any(a => a.Person.Id == noteWatchPersonToNotify.Person.Id)) { // Person Requested to NOT watch, now make sure that they aren't force to watch based on Override = False if (!noteWatchPersonToNotifyListNoOverride.Any(a => a.Person.Id == noteWatchPersonToNotify.Person.Id)) { // person requested to NOT watch, and there aren't any overrides to prevent that, so jump out to the next one continue; } } NoteWatchPersonToNotifyList personToNotifyList; if (personIdNotificationDigestList.ContainsKey(noteWatchPersonToNotify.Person.Id)) { // This just create a place holder for the Note referring to item in the digest by key of person personToNotifyList = personIdNotificationDigestList[noteWatchPersonToNotify.Person.Id] ?? new NoteWatchPersonToNotifyList(noteWatchPersonToNotify.Person); } else { // This just creates a new place holder for the Note in the digest personToNotifyList = new NoteWatchPersonToNotifyList(noteWatchPersonToNotify.Person); personIdNotificationDigestList.Add(noteWatchPersonToNotify.Person.Id, personToNotifyList); } // Only include the note if the watcher person is authorized to view the note if (noteWatchPersonToNotify.Note.IsAuthorized(Rock.Security.Authorization.VIEW, noteWatchPersonToNotify.Person)) { // This is where the get added to the item of the digest personToNotifyList.Add(noteWatchPersonToNotify); } } } }
/// <summary> /// Saves the person notes and history. /// </summary> /// <param name="registrationPersonFirstName">First name of the registration person.</param> /// <param name="registrationPersonLastName">Last name of the registration person.</param> /// <param name="currentPersonAliasId">The current person alias identifier.</param> /// <param name="previousRegistrantPersonIds">The previous registrant person ids.</param> public void SavePersonNotesAndHistory(string registrationPersonFirstName, string registrationPersonLastName, int?currentPersonAliasId, List <int> previousRegistrantPersonIds) { // Setup Note settings Registration registration = this; NoteTypeCache noteType = null; using (RockContext rockContext = new RockContext()) { RegistrationInstance registrationInstance = registration.RegistrationInstance ?? new RegistrationInstanceService(rockContext).Get(registration.RegistrationInstanceId); RegistrationTemplate registrationTemplate = registrationInstance.RegistrationTemplate ?? new RegistrationTemplateService(rockContext).Get(registrationInstance.RegistrationTemplateId); if (registrationTemplate != null && registrationTemplate.AddPersonNote) { noteType = NoteTypeCache.Get(Rock.SystemGuid.NoteType.PERSON_EVENT_REGISTRATION.AsGuid()); if (noteType != null) { var noteService = new NoteService(rockContext); var personAliasService = new PersonAliasService(rockContext); Person registrar = null; if (registration.PersonAliasId.HasValue) { registrar = personAliasService.GetPerson(registration.PersonAliasId.Value); } var registrantNames = new List <string>(); // Get each registrant foreach (var registrantPersonAliasId in registration.Registrants .Where(r => r.PersonAliasId.HasValue) .Select(r => r.PersonAliasId.Value) .ToList()) { var registrantPerson = personAliasService.GetPerson(registrantPersonAliasId); if (registrantPerson != null && (previousRegistrantPersonIds == null || !previousRegistrantPersonIds.Contains(registrantPerson.Id))) { var noteText = new StringBuilder(); noteText.AppendFormat("Registered for {0}", registrationInstance.Name); string registrarFullName = string.Empty; if (registrar != null && registrar.Id != registrantPerson.Id) { registrarFullName = string.Format(" by {0}", registrar.FullName); registrantNames.Add(registrantPerson.FullName); } if (registrar != null && (registrationPersonFirstName != registrar.NickName || registrationPersonLastName != registrar.LastName)) { registrarFullName = string.Format(" by {0}", registrationPersonFirstName + " " + registrationPersonLastName); } noteText.Append(registrarFullName); if (noteText.Length > 0) { var note = new Note(); note.NoteTypeId = noteType.Id; note.IsSystem = false; note.IsAlert = false; note.IsPrivateNote = false; note.EntityId = registrantPerson.Id; note.Caption = string.Empty; note.Text = noteText.ToString(); if (registrar == null) { note.CreatedByPersonAliasId = currentPersonAliasId; } else { note.CreatedByPersonAliasId = registrar.PrimaryAliasId; } noteService.Add(note); } var changes = new History.HistoryChangeList(); changes.AddChange(History.HistoryVerb.Registered, History.HistoryChangeType.Record, null); HistoryService.SaveChanges( rockContext, typeof(Person), Rock.SystemGuid.Category.HISTORY_PERSON_REGISTRATION.AsGuid(), registrantPerson.Id, changes, registrationInstance.Name, typeof(Registration), registration.Id, false, currentPersonAliasId, rockContext.SourceOfChange); } } if (registrar != null && registrantNames.Any()) { string namesText = string.Empty; if (registrantNames.Count >= 2) { int lessOne = registrantNames.Count - 1; namesText = registrantNames.Take(lessOne).ToList().AsDelimited(", ") + " and " + registrantNames.Skip(lessOne).Take(1).First() + " "; } else { namesText = registrantNames.First() + " "; } var note = new Note(); note.NoteTypeId = noteType.Id; note.IsSystem = false; note.IsAlert = false; note.IsPrivateNote = false; note.EntityId = registrar.Id; note.Caption = string.Empty; note.Text = string.Format("Registered {0} for {1}", namesText, registrationInstance.Name); noteService.Add(note); var changes = new History.HistoryChangeList(); changes.AddChange(History.HistoryVerb.Registered, History.HistoryChangeType.Record, namesText); HistoryService.SaveChanges( rockContext, typeof(Person), Rock.SystemGuid.Category.HISTORY_PERSON_REGISTRATION.AsGuid(), registrar.Id, changes, registrationInstance.Name, typeof(Registration), registration.Id, false, currentPersonAliasId, rockContext.SourceOfChange); } rockContext.SaveChanges(); } } } }