/// <summary> /// Loads the drop down items. /// </summary> /// <param name="picker">The picker.</param> /// <param name="includeEmptyOption">if set to <c>true</c> [include empty option].</param> public static void LoadDropDownItems(IStreakTypePicker picker, bool includeEmptyOption) { var selectedItems = picker.Items.Cast <ListItem>() .Where(i => i.Selected) .Select(i => i.Value).AsIntegerList(); picker.Items.Clear(); if (includeEmptyOption) { // add Empty option first picker.Items.Add(new ListItem()); } var streakTypes = StreakTypeCache.All() .Where(st => st.IsActive) .OrderBy(st => st.Name) .ThenBy(st => st.Id) .ToList(); foreach (var streakType in streakTypes) { var li = new ListItem(streakType.Name, streakType.Id.ToString()); li.Selected = selectedItems.Contains(streakType.Id); picker.Items.Add(li); } }
/// <summary> /// Returns a dictionary of the items available for selection. /// </summary> /// <returns></returns> protected override Dictionary <Guid, string> OnGetItemList() { return(StreakTypeCache.All() .Where(s => s.IsActive) .OrderBy(s => s.Name) .Select(s => new { s.Guid, s.Name, }) .ToDictionary(s => s.Guid, s => s.Name)); }
/// <summary> /// BulkInserts Interaction Records /// </summary> /// <remarks> /// If any PersonAliasId references a PersonAliasId record that doesn't exist, the field value will be set to null. /// Also, if the InteractionComponent Id (or Guid) is specified, but references a Interaction Component record that doesn't exist /// the Interaction will not be recorded. /// </remarks> /// <param name="interactionsImport">The interactions import.</param> internal static void BulkInteractionImport(InteractionsImport interactionsImport) { if (interactionsImport == null) { throw new Exception("InteractionsImport must be assigned a value."); } var interactionImportList = interactionsImport.Interactions; if (interactionImportList == null || !interactionImportList.Any()) { // if there aren't any return return; } /* 2020-05-14 MDP * Make sure that all the PersonAliasIds in the import exist in the database. * For performance reasons, look them up all at one and keep a list of valid ones. * * If there are any PersonAliasIds that aren't valid, * we decided that just set the PersonAliasId to null (we want ignore bad data). */ HashSet <int> validPersonAliasIds = interactionsImport.GetValidPersonAliasIds(); List <Interaction> interactionsToInsert = new List <Interaction>(); foreach (InteractionImport interactionImport in interactionImportList) { if (interactionImport.Interaction == null) { throw new ArgumentNullException("InteractionImport.Interaction can not be null"); } // Determine which Channel this should be set to if (interactionImport.InteractionChannelId.HasValue) { // make sure it is a valid Id interactionImport.InteractionChannelId = InteractionChannelCache.Get(interactionImport.InteractionChannelId.Value)?.Id; } // Determine which Channel Type Medium this should be set to if (interactionImport.InteractionChannelChannelTypeMediumValueId.HasValue) { // make sure it is a valid Id interactionImport.InteractionChannelChannelTypeMediumValueId = DefinedValueCache.Get(interactionImport.InteractionChannelChannelTypeMediumValueId.Value)?.Id; } if (!interactionImport.InteractionChannelChannelTypeMediumValueId.HasValue) { if (interactionImport.InteractionChannelChannelTypeMediumValueGuid.HasValue) { interactionImport.InteractionChannelChannelTypeMediumValueId = DefinedValueCache.GetId(interactionImport.InteractionChannelChannelTypeMediumValueGuid.Value); } } if (!interactionImport.InteractionChannelId.HasValue) { if (interactionImport.InteractionChannelGuid.HasValue) { interactionImport.InteractionChannelId = InteractionChannelCache.GetId(interactionImport.InteractionChannelGuid.Value); } // if InteractionChannelId is still null, lookup (or create) an InteractionChannel from InteractionChannelForeignKey (if it is specified) if (interactionImport.InteractionChannelId == null && interactionImport.InteractionChannelForeignKey.IsNotNullOrWhiteSpace()) { interactionImport.InteractionChannelId = InteractionChannelCache.GetCreateChannelIdByForeignKey(interactionImport.InteractionChannelForeignKey, interactionImport.InteractionChannelName, interactionImport.InteractionChannelChannelTypeMediumValueId); } else { /* 2020-05-14 MDP * Discussed this and decided that if we tried InteractionChannelId and InteractionChannelGuid, and InteractionChannelForeignKey was not specified, * we'll just skip over this record */ continue; } } // Determine which Component this should be set to if (interactionImport.InteractionComponentId.HasValue) { // make sure it is a valid Id interactionImport.InteractionComponentId = InteractionComponentCache.Get(interactionImport.InteractionComponentId.Value)?.Id; } if (!interactionImport.InteractionComponentId.HasValue) { if (interactionImport.InteractionComponentGuid.HasValue) { interactionImport.InteractionComponentId = InteractionComponentCache.GetId(interactionImport.InteractionComponentGuid.Value); } // if InteractionComponentId is still null, lookup (or create) an InteractionComponent from the ForeignKey and ChannelId if (interactionImport.InteractionComponentForeignKey.IsNotNullOrWhiteSpace()) { interactionImport.InteractionComponentId = InteractionComponentCache.GetComponentIdByForeignKeyAndChannelId( interactionImport.InteractionComponentForeignKey, interactionImport.InteractionChannelId.Value, interactionImport.InteractionComponentName); } else { /* 2020-05-14 MDP * Discussed this and decided that and if we tried InteractionComponentId and InteractionComponentGuid, and InteractionComponentForeignKey was not specified, * we'll just skip over this record */ continue; } } } foreach (InteractionImport interactionImport in interactionImportList.Where(a => a.InteractionComponentId.HasValue)) { Interaction interaction = new Interaction { InteractionComponentId = interactionImport.InteractionComponentId.Value }; interaction.InteractionDateTime = interactionImport.Interaction.InteractionDateTime; // if operation is over 25, truncate it interaction.Operation = interactionImport.Interaction.Operation.Truncate(25); interaction.InteractionComponentId = interactionImport.InteractionComponentId.Value; interaction.EntityId = interactionImport.Interaction.EntityId; if (interactionImport.Interaction.RelatedEntityTypeId.HasValue) { /* 2020-05-14 MDP * We want to ignore bad data, so first see if the RelatedEntityTypeId exists by looking it up in a cache. * If it doesn't exist, it'll set RelatedEntityTypeId to null (so that we don't get a database constraint error) */ interaction.RelatedEntityTypeId = EntityTypeCache.Get(interactionImport.Interaction.RelatedEntityTypeId.Value)?.Id; } interaction.RelatedEntityId = interactionImport.Interaction.RelatedEntityId; if (interactionImport.Interaction.PersonAliasId.HasValue) { /* 2020-05-14 MDP * We want to ignore bad data, so see if the specified PersonAliasId exists in the validPersonAliasIds that we lookup up * If it doesn't exist, we'll leave interaction.PersonAliasId null (so that we don't get a database constraint error) */ if (validPersonAliasIds.Contains(interactionImport.Interaction.PersonAliasId.Value)) { interaction.PersonAliasId = interactionImport.Interaction.PersonAliasId.Value; } } // BulkImport doesn't include Session information TODO??? interaction.InteractionSessionId = null; // if the summary is over 500 chars, truncate with addEllipsis=true interaction.InteractionSummary = interactionImport.Interaction.InteractionSummary.Truncate(500, true); interaction.InteractionData = interactionImport.Interaction.InteractionData; interaction.PersonalDeviceId = interactionImport.Interaction.PersonalDeviceId; interaction.InteractionEndDateTime = interactionImport.Interaction.InteractionEndDateTime; // Campaign related fields, we'll truncate those if they are too long interaction.Source = interactionImport.Interaction.Source.Truncate(25); interaction.Medium = interactionImport.Interaction.Medium.Truncate(25); interaction.Campaign = interactionImport.Interaction.Campaign.Truncate(50); interaction.Content = interactionImport.Interaction.Content.Truncate(50); interaction.Term = interactionImport.Interaction.Term.Truncate(50); interaction.ForeignId = interactionImport.Interaction.ForeignId; interaction.ForeignKey = interactionImport.Interaction.ForeignKey; interaction.ForeignGuid = interactionImport.Interaction.ForeignGuid; interaction.ChannelCustom1 = interactionImport.Interaction.ChannelCustom1.Truncate(500, true); interaction.ChannelCustom2 = interactionImport.Interaction.ChannelCustom2.Truncate(2000, true); interaction.ChannelCustomIndexed1 = interactionImport.Interaction.ChannelCustomIndexed1.Truncate(500, true); interaction.InteractionLength = interactionImport.Interaction.InteractionLength; interaction.InteractionTimeToServe = interactionImport.Interaction.InteractionTimeToServe; interactionsToInsert.Add(interaction); } using (var rockContext = new RockContext()) { rockContext.BulkInsert(interactionsToInsert); } // This logic is normally handled in the Interaction.PostSave method, but since the BulkInsert bypasses those // model hooks, streaks need to be updated here. Also, it is not necessary for this logic to complete before this // transaction can continue processing and exit, so update the streak using a task. // Only launch this task if there are StreakTypes configured that have interactions. Otherwise several // database calls are made only to find out there are no streak types defined. if (StreakTypeCache.All().Any(s => s.IsInteractionRelated)) { // Ids do not exit for the interactions in the collection since they were bulk imported. // Read their ids from their guids and append the id. var insertedGuids = interactionsToInsert.Select(i => i.Guid).ToList(); var interactionIds = new InteractionService(new RockContext()).Queryable() .Where(i => insertedGuids.Contains(i.Guid)) .Select(i => new { i.Id, i.Guid }) .ToList(); foreach (var interactionId in interactionIds) { var interaction = interactionsToInsert.Where(i => i.Guid == interactionId.Guid).FirstOrDefault(); if (interaction != null) { interaction.Id = interactionId.Id; } } // Launch task interactionsToInsert.ForEach(i => Task.Run(() => StreakTypeService.HandleInteractionRecord(i.Id))); } }
/// <summary> /// Logs the interactions. /// </summary> /// <param name="interactionTransactionInfos">The interaction transaction infos to process.</param> /// <param name="rockContext">The rock context.</param> private void LogInteractions(List <InteractionTransactionInfo> interactionTransactionInfos, RockContext rockContext) { List <Interaction> interactionsToInsert = new List <Interaction>(); var interactionService = new InteractionService(rockContext); foreach (var info in interactionTransactionInfos.Where(a => a.InteractionComponentId.HasValue)) { /* * 2020-06-29 - JH * * The 'CreateInteraction(...)' method called below sets the following properties on the Interaction object: * * - InteractionComponentId * - InteractionDateTime (but with the wrong value) * - InteractionSessionId * - Source * - Medium * - Campaign * - Content * - Term */ var interaction = interactionService.CreateInteraction(info.InteractionComponentId.Value, info.UserAgent, info.InteractionData, info.IPAddress, info.BrowserSessionId); // The rest of the properties need to be manually set. interaction.EntityId = info.InteractionEntityId; interaction.Operation = info.InteractionOperation.IsNotNullOrWhiteSpace() ? info.InteractionOperation.Trim() : "View"; interaction.InteractionSummary = info.InteractionSummary?.Trim(); interaction.PersonAliasId = info.PersonAliasId; interaction.InteractionDateTime = info.InteractionDateTime; interaction.InteractionTimeToServe = info.InteractionTimeToServe; interaction.RelatedEntityTypeId = info.InteractionRelatedEntityTypeId; interaction.RelatedEntityId = info.InteractionRelatedEntityId; interaction.ChannelCustom1 = info.InteractionChannelCustom1?.Trim(); interaction.ChannelCustom2 = info.InteractionChannelCustom2?.Trim(); interaction.ChannelCustomIndexed1 = info.InteractionChannelCustomIndexed1?.Trim(); interaction.Source = interaction.Source ?? info.InteractionSource?.Trim(); interaction.Medium = interaction.Medium ?? info.InteractionMedium?.Trim(); interaction.Campaign = interaction.Campaign ?? info.InteractionCampaign?.Trim(); interaction.Content = interaction.Content ?? info.InteractionContent?.Trim(); interaction.Term = interaction.Term ?? info.InteractionTerm?.Trim(); interaction.InteractionLength = info.InteractionLength; interaction.InteractionEndDateTime = info.InteractionEndDateTime; interaction.SetInteractionData(info.InteractionData?.Trim()); interactionsToInsert.Add(interaction); } rockContext.BulkInsert(interactionsToInsert); // This logic is normally handled in the Interaction.PostSave method, but since the BulkInsert bypasses those // model hooks, streaks need to be updated here. Also, it is not necessary for this logic to complete before this // transaction can continue processing and exit, so update the streak using a task. // Only launch this task if there are StreakTypes configured that have interactions. Otherwise several // database calls are made only to find out there are no streak types defined. if (StreakTypeCache.All().Any(s => s.IsInteractionRelated)) { // Ids do not exit for the interactions in the collection since they were bulk imported. // Read their ids from their guids and append the id. var insertedGuids = interactionsToInsert.Select(i => i.Guid).ToList(); var interactionIds = new InteractionService(new RockContext()).Queryable() .Where(i => insertedGuids.Contains(i.Guid)) .Select(i => new { i.Id, i.Guid }) .ToList(); foreach (var interactionId in interactionIds) { var interaction = interactionsToInsert.Where(i => i.Guid == interactionId.Guid).FirstOrDefault(); if (interaction != null) { interaction.Id = interactionId.Id; } } // Launch task interactionsToInsert.ForEach(i => Task.Run(() => StreakTypeService.HandleInteractionRecord(i.Id))); } }