/// <summary> /// Finds any missing personal link section orders /// and <see cref="Rock.Data.Service{T}.Add(T)">adds</see> them (but doesn't .SaveChanges) /// If this returns true, call SaveChanges to save them to the database. /// </summary> /// <param name="currentPerson">The current person.</param> /// <returns>List<PersonalLinkSectionOrder>.</returns> public bool AddMissingPersonalLinkSectionOrders(Person currentPerson) { var primaryAliasId = currentPerson.PrimaryAliasId; if (!primaryAliasId.HasValue) { // shouldn't happen, but just in case return(false); } var rockContext = this.Context as RockContext; var personalLinkSectionService = new PersonalLinkSectionService(rockContext); var personAliasQuery = new PersonAliasService(rockContext).Queryable().Where(a => a.PersonId == currentPerson.Id); var personalLinkSectionsQuery = personalLinkSectionService .Queryable() .Where(a => a.IsShared || (a.PersonAliasId.HasValue && personAliasQuery.Any(aa => aa.Id == a.PersonAliasId.Value))); var missingSectionOrders = personalLinkSectionsQuery .Where(a => !a.PersonalLinkSectionOrders.Any(xx => personAliasQuery.Any(pa => pa.Id == xx.PersonAliasId))) .ToList() .OrderBy(a => a.Name) .Select(a => new PersonalLinkSectionOrder { PersonAliasId = primaryAliasId.Value, SectionId = a.Id, Order = 0 }).ToList(); if (missingSectionOrders.Any()) { // add the new order for sections to the bottom of the list for that section (in order by name) var personalLinkSectionOrderService = new PersonalLinkSectionOrderService(rockContext); var lastSectionOrder = personalLinkSectionOrderService.Queryable().Where(a => a.PersonAlias.PersonId == currentPerson.Id).Max(a => ( int? )a.Order) ?? 0; foreach (var missingSectionOrder in missingSectionOrders) { missingSectionOrder.Order = lastSectionOrder++; } personalLinkSectionOrderService.AddRange(missingSectionOrders); return(true); } else { return(false); } }
/// <summary> /// Gets the section order query. /// Use this to make sure to get the best match for in cases where /// a person has more than one sort order for a section (which could happen if there was person merge) /// </summary> /// <remarks> /// If you are unsure if there are some sections that don't have an order, use <see cref="AddMissingPersonalLinkSectionOrders(Person)"/> first. /// </remarks> /// <param name="person">The person.</param> /// <returns>System.Linq.IQueryable<Rock.Model.PersonalLinkSectionOrder>.</returns> public IOrderedQueryable <PersonalLinkSectionOrder> GetSectionOrderQuery(Person person) { var rockContext = this.Context as RockContext; var personAliasQuery = new PersonAliasService(rockContext).Queryable().Where(a => a.PersonId == person.Id); // There could be duplicate Orders for a Section for a person if the person was merged. // So, to ensure a consistent Order winner, also sort by ModifiedDateTime. That will // ensure the the most recent sort will be one the current person sees. var personalLinkSectionOrder = new PersonalLinkSectionOrderService(rockContext).Queryable() .Where(a => personAliasQuery.Any(xx => xx.Id == a.PersonAliasId)) .GroupBy(a => a.SectionId) .Select(a => a.OrderBy(xx => xx.Order).ThenByDescending(xx => xx.ModifiedDateTime).FirstOrDefault()) .OrderBy(a => a.Order); return(personalLinkSectionOrder); }
/// <summary> /// Creates the email communication. /// </summary> /// <param name="createEmailCommunicationArgs">The create email communication arguments.</param> /// <returns></returns> public Communication CreateEmailCommunication(CreateEmailCommunicationArgs createEmailCommunicationArgs) { var recipients = createEmailCommunicationArgs.Recipients; var senderPersonAliasId = createEmailCommunicationArgs.SenderPersonAliasId; var fromName = createEmailCommunicationArgs.FromName; var fromAddress = createEmailCommunicationArgs.FromAddress; var replyTo = createEmailCommunicationArgs.ReplyTo; var subject = createEmailCommunicationArgs.Subject; var message = createEmailCommunicationArgs.Message; var bulkCommunication = createEmailCommunicationArgs.BulkCommunication; var sendDateTime = createEmailCommunicationArgs.SendDateTime; var recipientStatus = createEmailCommunicationArgs.RecipientStatus; var systemCommunicationId = createEmailCommunicationArgs.SystemCommunicationId; var recipientsWithPersonIds = recipients.Where(a => a.PersonId.HasValue).Select(a => a.PersonId).ToList(); var recipientEmailsUnknownPersons = recipients.Where(a => a.PersonId == null).Select(a => a.EmailAddress); /* * 4-MAY-2022 DMV * * In tracking down alleged duplicate communications we discovered * that duplicates could be sent to the same person if they are in the * recipient list more that once with mulitple Person Alias IDs. * This could have occured through a person merge or other data changes * in Rock. This code removes those duplicates from the list before * sending the communication. * */ var recipientPersonList = new PersonAliasService(( RockContext )Context) .GetPrimaryAliasQuery() .Where(pa => recipientsWithPersonIds.Contains(pa.PersonId)) .Select(a => a.Person) .ToList(); if (!recipientPersonList.Any() && recipientEmailsUnknownPersons.Any(a => a != null)) { // For backwards compatibility, if no PersonIds where specified, but there are recipients that are only specified by EmailAddress, take a guess at the personIds by looking for matching email addresses recipientPersonList = new PersonService(( RockContext )Context) .Queryable() .Where(p => recipientEmailsUnknownPersons.Contains(p.Email)) .ToList(); } if (!recipientPersonList.Any()) { return(null); } var communication = new Communication { CommunicationType = CommunicationType.Email, Status = CommunicationStatus.Approved, ReviewedDateTime = RockDateTime.Now, ReviewerPersonAliasId = senderPersonAliasId, SenderPersonAliasId = senderPersonAliasId }; communication.FromName = fromName.TrimForMaxLength(communication, "FromName"); communication.FromEmail = fromAddress.TrimForMaxLength(communication, "FromEmail"); communication.ReplyToEmail = replyTo.TrimForMaxLength(communication, "ReplyToEmail"); communication.Subject = subject.TrimForMaxLength(communication, "Subject"); communication.Message = message; communication.IsBulkCommunication = bulkCommunication; communication.FutureSendDateTime = null; communication.SendDateTime = sendDateTime; communication.SystemCommunicationId = systemCommunicationId; Add(communication); // add each person as a recipient to the communication foreach (var person in recipientPersonList) { var personAliasId = person.PrimaryAliasId; if (!personAliasId.HasValue) { continue; } var communicationRecipient = new CommunicationRecipient { PersonAliasId = personAliasId.Value, Status = recipientStatus, SendDateTime = sendDateTime }; communication.Recipients.Add(communicationRecipient); } return(communication); }
/// <summary> /// Gets current login's LastModifiedDateTime <see cref="Rock.Model.PersonalLink" /> data from <see cref="System.Web.SessionState">Session</see>. /// </summary> /// <remarks> /// We cache PersonalLinksLastUpdateDateTime in session so that we know if the LocalStorage of PersonalLinks needs to be updated. /// </remarks> public static DateTime?GetPersonalLinksLastModifiedDateTime(Person currentPerson) { if (currentPerson == null) { return(null); } DateTime?lastModifiedDateTime = null; if (HttpContext.Current?.Session != null) { // If we already got the LastModifiedDateTime, we'll store it in session so that we don't have to keep asking lastModifiedDateTime = HttpContext.Current.Session[SessionKey.PersonalLinksLastUpdateDateTime] as DateTime?; } else { // If we dont' have a Session, see if we are storing it for the current request; lastModifiedDateTime = HttpContext.Current?.Items[SessionKey.PersonalLinksLastUpdateDateTime] as DateTime?; } if (lastModifiedDateTime.HasValue) { return(lastModifiedDateTime); } // NOTE: Session can be null (probably because it is a REST call). Or maybe it hasn't been set in Session yet So, we'll get it from the Database; var rockContext = new RockContext(); var personAliasQuery = new PersonAliasService(rockContext).Queryable().Where(a => a.PersonId == currentPerson.Id); var sectionLastModifiedDateTimeQuery = new PersonalLinkSectionService(rockContext) .Queryable() .Where(a => !a.IsShared && a.ModifiedDateTime.HasValue && a.PersonAliasId.HasValue && personAliasQuery.Any(x => x.Id == a.PersonAliasId)) .Select(a => a.ModifiedDateTime); var linkLastModifiedDateTimeQuery = new PersonalLinkService(rockContext) .Queryable() .Where(a => a.ModifiedDateTime.HasValue && a.PersonAliasId.HasValue && personAliasQuery.Any(x => x.Id == a.PersonAliasId)) .Select(a => a.ModifiedDateTime); var linkOrderLastModifiedDateTimeQuery = new PersonalLinkSectionOrderService(rockContext) .Queryable() .Where(a => a.ModifiedDateTime.HasValue && personAliasQuery.Any(x => x.Id == a.PersonAliasId)) .Select(a => a.ModifiedDateTime); lastModifiedDateTime = sectionLastModifiedDateTimeQuery.Union(linkLastModifiedDateTimeQuery).Union(linkOrderLastModifiedDateTimeQuery).Max(a => a); if (HttpContext.Current?.Session != null) { if (lastModifiedDateTime == null) { // If LastModifiedDateTime is still null, they don't have any personal links, // So we'll set LastModifiedDateTime to Midnight (so it doesn't keep checking the database) lastModifiedDateTime = RockDateTime.Today; } // If we already got the LastModifiedDateTime, we'll store it in session so that we don't have to keep asking HttpContext.Current.Session[SessionKey.PersonalLinksLastUpdateDateTime] = lastModifiedDateTime; } else { // if we don't have Session, store it in the current request (just in case this called multiple times in the same request) if (HttpContext.Current != null) { HttpContext.Current.Items[SessionKey.PersonalLinksLastUpdateDateTime] = lastModifiedDateTime; } } return(lastModifiedDateTime); }
/// <summary> /// Returns a queryable of the ordered personal link sections (shared and non-shared) that would be available to the specified person. /// They will be sorted by the order that the specified person put them in, /// </summary> /// <param name="currentPerson">The current person.</param> /// <returns>IOrderedQueryable<PersonalLinkSection>.</returns> public IOrderedQueryable <PersonalLinkSection> GetOrderedPersonalLinkSectionsQuery(Person currentPerson) { var rockContext = this.Context as RockContext; var personAliasQuery = new PersonAliasService(rockContext).Queryable().Where(a => a.PersonId == currentPerson.Id); var sectionOrderQuery = GetSectionOrderQuery(currentPerson); var orderedPersonalLinkSectionQuery = new PersonalLinkSectionService(rockContext) .Queryable() .Where(a => a.IsShared || (a.PersonAliasId.HasValue && personAliasQuery.Any(xx => xx.Id == a.PersonAliasId.Value))) .OrderBy(a => sectionOrderQuery.Where(xx => xx.SectionId == a.Id).Select(s => s.Order).FirstOrDefault()) .ThenBy(a => a.Name); return(orderedPersonalLinkSectionQuery); }