/// <summary> /// Method that will be called on an entity immediately after the item is saved by context /// </summary> /// <param name="dbContext">The database context.</param> /// <param name="entry">The entry.</param> /// <param name="state">The state.</param> public override void PreSaveChanges(Data.DbContext dbContext, DbEntityEntry entry, EntityState state) { if (state == EntityState.Added) { var noteType = NoteTypeCache.Get(this.NoteTypeId); if (noteType?.AutoWatchAuthors == true) { // if this is a new note, and AutoWatchAuthors, then add a NoteWatch so the author will get notified when there are any replies var rockContext = dbContext as RockContext; if (rockContext != null && this.CreatedByPersonAliasId.HasValue) { var noteWatchService = new NoteWatchService(rockContext); // we don't know the Note.Id yet, so just assign the NoteWatch.Note and EF will populate the NoteWatch.NoteId automatically var noteWatch = new NoteWatch { IsWatching = true, WatcherPersonAliasId = this.CreatedByPersonAliasId.Value, Note = this }; noteWatchService.Add(noteWatch); } } } base.PreSaveChanges(dbContext, entry, state); }
/// <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> /// Returns all Non-Overridable NoteWatches that would prevent this NoteWatch from enabling IsWatching=False /// Returns a Queryable of zero or more NoteWatches /// </summary> /// <param name="rockContext">The rock context.</param> /// <returns> /// <c>true</c> if [is allowed to unwatch]; otherwise, <c>false</c>. /// </returns> public IQueryable <NoteWatch> GetNonOverridableNoteWatches(RockContext rockContext) { var noteWatchService = new NoteWatchService(rockContext); // we are only concerned about other IsWatching watches that don't allow overrides var noteWatchesWithOverrideNotAllowedQuery = noteWatchService.Queryable().Where(a => a.AllowOverride == false && a.IsWatching && a.Id != this.Id); // limit to notewatches for the same watcher person (or where the watcher person is part of the watcher group) if (this.WatcherPersonAliasId.HasValue) { var watcherPerson = this.WatcherPersonAlias?.Person ?? new PersonAliasService(rockContext).Get(this.WatcherPersonAliasId.Value).Person; // limit to watch that are watched by the same person, or watched by a group that a person is an active member of noteWatchesWithOverrideNotAllowedQuery = noteWatchesWithOverrideNotAllowedQuery .Where(a => a.WatcherPersonAliasId.HasValue && a.WatcherPersonAlias.PersonId == this.WatcherPersonAlias.PersonId || a.WatcherGroup.Members.Any(gm => gm.GroupMemberStatus == GroupMemberStatus.Active && gm.Person.Aliases.Any(x => x.PersonId == watcherPerson.Id)) ); } else if (this.WatcherGroupId.HasValue) { // if the watcher is a Group, make sure it isn't trying to override another watch where the watcher is the same group noteWatchesWithOverrideNotAllowedQuery = noteWatchesWithOverrideNotAllowedQuery.Where(a => a.WatcherGroupId.HasValue && a.WatcherGroupId.Value == this.WatcherGroupId.Value); } else { // invalid NoteWatch so just return a false query (no records) return(noteWatchesWithOverrideNotAllowedQuery.Where(a => false)); } NoteTypeCache noteType = null; if (this.NoteTypeId.HasValue) { noteType = NoteTypeCache.Get(this.NoteTypeId.Value); } var noteWatchEntityTypeId = this.EntityTypeId ?? noteType?.EntityTypeId; //// Find NoteWatches that could override this note watch //// We are mostly looking for NoteWatches that are the same or less specific than this watch // at a minimum, the EntityType must be the same noteWatchesWithOverrideNotAllowedQuery = noteWatchesWithOverrideNotAllowedQuery.Where(a => (a.EntityTypeId.HasValue && a.EntityTypeId.Value == noteWatchEntityTypeId) || (a.NoteTypeId.HasValue && a.NoteType.EntityTypeId == noteWatchEntityTypeId)); // look for non-overridable notewatches that not specific to a NoteType, NoteId, or Entity,etc var globalEntityTypeNoteWatchesWithNoOverridesQuery = noteWatchesWithOverrideNotAllowedQuery.Where(a => a.NoteTypeId == null && a.NoteId == null && a.EntityId == null); if (globalEntityTypeNoteWatchesWithNoOverridesQuery.Any()) { // found at least one non-overridable notewatch that covers all notes for the note watch, so it any attempt to unwatch wouldn't block due to the override return(globalEntityTypeNoteWatchesWithNoOverridesQuery); } // if this notewatch is more specific, look for ones that are the same or less specific if (this.NoteTypeId.HasValue) { var noteTypeNoteWatchesWithNoOverridesQuery = noteWatchesWithOverrideNotAllowedQuery.Where(a => (a.NoteTypeId.HasValue && a.NoteTypeId.Value == this.NoteTypeId.Value) && a.NoteId == null && a.EntityId == null); if (noteTypeNoteWatchesWithNoOverridesQuery.Any()) { // found at least one non-overridable notewatch that covers all notes for the note watch and NoteType, so it any attempt to unwatch wouldn't block due to the override return(noteTypeNoteWatchesWithNoOverridesQuery); } } if (this.NoteId.HasValue) { var noteNoteWatchesWithNoOverridesQuery = noteWatchesWithOverrideNotAllowedQuery.Where(a => (a.NoteId.HasValue && a.NoteId.Value == this.NoteId.Value) && a.EntityId == null); if (noteNoteWatchesWithNoOverridesQuery.Any()) { // found at least one non-overridable notewatch that covers this exact note for the note watch, so it any attempt to unwatch wouldn't block due to the override return(noteNoteWatchesWithNoOverridesQuery); } } if (this.EntityId.HasValue) { var entityNoteWatchesWithNoOverridesQuery = noteWatchesWithOverrideNotAllowedQuery.Where(a => a.NoteTypeId == null && a.NoteId == null && (a.EntityId.HasValue && (a.EntityId == this.EntityId.Value))); if (entityNoteWatchesWithNoOverridesQuery.Any()) { // found at least one non-overridable notewatch that covers this exact same entity for the note watch, so it any attempt to unwatch wouldn't block due to the override return(entityNoteWatchesWithNoOverridesQuery); } } // no non-overridable conditions found, so return a false query (no records) return(noteWatchesWithOverrideNotAllowedQuery.Where(a => false)); }