/// <summary>
        /// Create interaction data
        /// </summary>
        private static void CreateInteractionData()
        {
            _interactionComponent = InteractionComponentCache.All().FirstOrDefault(i => i.InteractionChannel.Guid == SystemGuid.InteractionChannel.ROCK_RMS.AsGuid());

            var existing = _interactionService.Queryable().Where(i =>
                                                                 _personAliasIds.Contains(i.PersonAliasId.Value) &&
                                                                 i.InteractionComponentId == _interactionComponent.Id
                                                                 );

            _interactionService.DeleteRange(existing);

            for (var i = 0; i < COUNT; i++)
            {
                _interactionService.Add(new Interaction
                {
                    InteractionComponentId = _interactionComponent.Id,
                    PersonAliasId          = _personAliasIds[i % NUMBER_OF_ALIASES],
                    InteractionDateTime    = RockDateTime.Today,
                    ForeignKey             = KEY,
                    ForeignId = i
                });
            }

            _rockContext.SaveChanges(true);
        }
        /// <summary>
        /// Should the achievement type process attempts if the given source entity has been modified in some way.
        /// </summary>
        /// <param name="achievementTypeCache">The achievement type cache.</param>
        /// <param name="sourceEntity">The source entity.</param>
        /// <returns></returns>
        public override bool ShouldProcess(AchievementTypeCache achievementTypeCache, IEntity sourceEntity)
        {
            var interaction = sourceEntity as Interaction;

            if (interaction == null)
            {
                return(false);
            }

            var channel = GetInteractionChannelCache(achievementTypeCache);

            if (channel == null)
            {
                return(true);
            }

            var component = GetInteractionComponentCache(achievementTypeCache);

            if (component == null)
            {
                component = InteractionComponentCache.Get(interaction.InteractionComponentId);
                return(component.InteractionChannelId == channel.Id);
            }

            return(interaction.InteractionComponentId == component.Id);
        }
Esempio n. 3
0
        /// <summary>
        /// Gets the models from the delimited values.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="interactionChannel">The interactionChannel</param>
        /// <param name="interactionComponent">The interactionComponent</param>
        private void GetModelsFromAttributeValue(string value, out InteractionChannelCache interactionChannel, out InteractionComponentCache interactionComponent)
        {
            interactionChannel   = null;
            interactionComponent = null;

            ParseDelimitedGuids(value, out var interactionChannelGuid, out var interactionComponentGuid);

            if (interactionChannelGuid.HasValue || interactionComponentGuid.HasValue)
            {
                if (interactionChannelGuid.HasValue)
                {
                    interactionChannel = InteractionChannelCache.Get(interactionChannelGuid.Value);
                }

                if (interactionComponentGuid.HasValue)
                {
                    interactionComponent = InteractionComponentCache.Get(interactionComponentGuid.Value);
                }
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Reads new values entered by the user for the field ( as Guid )
        /// </summary>
        /// <param name="control">Parent control that controls were added to in the CreateEditControl() method</param>
        /// <param name="configurationValues">The configuration values.</param>
        /// <returns></returns>
        public override string GetEditValue(Control control, Dictionary <string, ConfigurationValue> configurationValues)
        {
            var interactionChannelInteractionComponentPicker = control as InteractionChannelInteractionComponentPicker;

            if (interactionChannelInteractionComponentPicker != null)
            {
                var  rockContext              = new RockContext();
                Guid?interactionChannelGuid   = null;
                Guid?interactionComponentGuid = null;

                if (interactionChannelInteractionComponentPicker.InteractionChannelId.HasValue)
                {
                    var channel = InteractionChannelCache.Get(interactionChannelInteractionComponentPicker.InteractionChannelId.Value);

                    if (channel != null)
                    {
                        interactionChannelGuid = channel.Guid;
                    }
                }

                if (interactionChannelInteractionComponentPicker.InteractionComponentId.HasValue)
                {
                    var component = InteractionComponentCache.Get(interactionChannelInteractionComponentPicker.InteractionComponentId.Value);

                    if (component != null)
                    {
                        interactionComponentGuid = component.Guid;
                    }
                }

                if (interactionChannelGuid.HasValue || interactionComponentGuid.HasValue)
                {
                    return(string.Format("{0}|{1}", interactionChannelGuid, interactionComponentGuid));
                }
            }

            return(null);
        }
Esempio n. 5
0
        /// <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)));
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Gets the component.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="channel">The channel.</param>
        /// <param name="entityId">The entity identifier.</param>
        /// <param name="identifier">The identifier.</param>
        /// <returns></returns>
        private InteractionComponentCache GetComponent(RockContext rockContext, InteractionChannelCache channel, int?entityId, string identifier)
        {
            if (channel != null)
            {
                if (entityId.HasValue)
                {
                    // Find by the Entity Id
                    int?interactionComponentId = new InteractionComponentService(rockContext)
                                                 .Queryable()
                                                 .AsNoTracking()
                                                 .Where(c => c.EntityId.HasValue && c.InteractionChannelId == channel.Id && c.EntityId.Value == entityId.Value)
                                                 .Select(c => c.Id)
                                                 .Cast <int?>()
                                                 .FirstOrDefault();

                    if (interactionComponentId != null)
                    {
                        return(InteractionComponentCache.Get(interactionComponentId.Value));
                    }
                }

                if (identifier.IsNotNullOrWhiteSpace())
                {
                    // Find by Id
                    int?id = identifier.AsIntegerOrNull();
                    if (id.HasValue)
                    {
                        var component = InteractionComponentCache.Get(id.Value);
                        if (component != null && component.InteractionChannelId == channel.Id)
                        {
                            return(component);
                        }
                    }

                    // Find by Guid
                    Guid?guid = identifier.AsGuidOrNull();
                    if (guid.HasValue)
                    {
                        var component = InteractionComponentCache.Get(guid.Value);
                        if (component != null && component.InteractionChannelId == channel.Id)
                        {
                            return(component);
                        }
                    }

                    if (!id.HasValue && !guid.HasValue)
                    {
                        // Find by Name
                        int?interactionComponentId = new InteractionComponentService(rockContext)
                                                     .Queryable()
                                                     .AsNoTracking()
                                                     .Where(c => c.InteractionChannelId == channel.Id)
                                                     .Where(c => c.Name.Equals(identifier, StringComparison.OrdinalIgnoreCase))
                                                     .Select(c => c.Id)
                                                     .Cast <int?>()
                                                     .FirstOrDefault();

                        if (interactionComponentId != null)
                        {
                            return(InteractionComponentCache.Get(interactionComponentId.Value));
                        }

                        // If still no match, and we have a name, create a new channel
                        using (var newRockContext = new RockContext())
                        {
                            var interactionComponent = new InteractionComponent();
                            interactionComponent.Name = identifier;
                            interactionComponent.InteractionChannelId = channel.Id;
                            new InteractionComponentService(newRockContext).Add(interactionComponent);
                            newRockContext.SaveChanges();

                            return(InteractionComponentCache.Get(interactionComponent.Id));
                        }
                    }
                }
            }

            return(null);
        }
Esempio n. 7
0
 /// <summary>
 /// Updates any Cache Objects that are associated with this entity
 /// </summary>
 /// <param name="entityState">State of the entity.</param>
 /// <param name="dbContext">The database context.</param>
 public void UpdateCache(EntityState entityState, Rock.Data.DbContext dbContext)
 {
     InteractionComponentCache.UpdateCachedEntity(this.Id, this.SaveState);
 }
Esempio n. 8
0
 /// <summary>
 /// Gets the cache object associated with this Entity
 /// </summary>
 /// <returns></returns>
 public IEntityCache GetCacheObject()
 {
     return(InteractionComponentCache.Get(this.Id));
 }
        /// <summary>
        /// Further configure this info object based on the options specified by the caller, then enqueue it to be bulk inserted.
        /// </summary>
        /// <param name="queue">The <see cref="ConcurrentQueue{InterationInfo}"/> into which this info object should be enqueued.</param>
        public void Initialize(ConcurrentQueue <InteractionTransactionInfo> queue)
        {
            RockPage    rockPage = null;
            HttpRequest request  = null;

            if (this.GetValuesFromHttpRequest)
            {
                try
                {
                    rockPage = HttpContext.Current.Handler as RockPage;
                }
                catch
                {
                    rockPage = null;
                }

                try
                {
                    if (rockPage != null)
                    {
                        request = rockPage.Request;
                    }
                    else if (HttpContext.Current != null)
                    {
                        request = HttpContext.Current.Request;
                    }
                }
                catch
                {
                    // Intentionally ignore exception (.Request will throw an exception instead of simply returning null if it isn't available).
                }
            }

            // Fall back to values from the HTTP request if specified by the caller AND the values weren't explicitly set on the info object:
            // (The rockPage and request variables will only be defined if this.GetValuesFromHttpRequest was true.)

            this.InteractionData = this.InteractionData ?? request?.Url.ToString();
            this.UserAgent       = this.UserAgent ?? request?.UserAgent;

            try
            {
                this.IPAddress = this.IPAddress ?? RockPage.GetClientIpAddress();
            }
            catch
            {
                this.IPAddress = string.Empty;
            }

            this.BrowserSessionId = this.BrowserSessionId ?? rockPage?.Session["RockSessionId"]?.ToString().AsGuidOrNull();

            this.PersonAliasId = this.PersonAliasId ?? rockPage?.CurrentPersonAliasId;

            // Make sure we don't exceed this field's character limit.
            this.InteractionOperation = EnforceLengthLimitation(this.InteractionOperation, 25);

            if (this.InteractionSummary.IsNullOrWhiteSpace())
            {
                // If InteractionSummary was not specified, use the Page title.
                var title = string.Empty;
                if (rockPage != null)
                {
                    if (rockPage.BrowserTitle.IsNotNullOrWhiteSpace())
                    {
                        title = rockPage.BrowserTitle;
                    }
                    else
                    {
                        title = rockPage.PageTitle;
                    }
                }

                // Remove the site name from the title.
                if (title?.Contains("|") == true)
                {
                    title = title.Substring(0, title.LastIndexOf('|')).Trim();
                }

                this.InteractionSummary = title;
            }

            // Make sure we don't exceed these fields' character limit.
            this.InteractionSummary               = EnforceLengthLimitation(this.InteractionSummary, 500);
            this.InteractionChannelCustom1        = EnforceLengthLimitation(this.InteractionChannelCustom1, 500);
            this.InteractionChannelCustom2        = EnforceLengthLimitation(this.InteractionChannelCustom2, 2000);
            this.InteractionChannelCustomIndexed1 = EnforceLengthLimitation(this.InteractionChannelCustomIndexed1, 500);
            this.InteractionSource   = EnforceLengthLimitation(this.InteractionSource, 25);
            this.InteractionMedium   = EnforceLengthLimitation(this.InteractionMedium, 25);
            this.InteractionCampaign = EnforceLengthLimitation(this.InteractionCampaign, 50);
            this.InteractionContent  = EnforceLengthLimitation(this.InteractionContent, 50);
            this.InteractionTerm     = EnforceLengthLimitation(this.InteractionTerm, 50);

            // Get existing (or create new) interaction channel and interaction component for this interaction.
            if (this.InteractionChannelId == default)
            {
                this.InteractionChannelId = InteractionChannelCache.GetChannelIdByTypeIdAndEntityId(this.ChannelTypeMediumValueId, this.ChannelEntityId, this.ChannelName, this.ComponentEntityTypeId, this.InteractionEntityTypeId);
            }

            this.InteractionComponentId = InteractionComponentCache.GetComponentIdByChannelIdAndEntityId(this.InteractionChannelId, this.ComponentEntityId, this.ComponentName);

            queue.Enqueue(this);
        }
Esempio n. 10
0
        public MediaElementInteraction GetWatchInteraction([FromUri] Guid?mediaElementGuid = null, [FromUri] Guid?personGuid = null, Guid?personAliasGuid = null)
        {
            var rockContext        = Service.Context as RockContext;
            var personService      = new PersonService(rockContext);
            var personAliasService = new PersonAliasService(rockContext);
            var interactionService = new InteractionService(rockContext);
            int?personAliasId;

            // Get the person alias to associate with the interaction in
            // order of provided Person.Guid, then PersonAlias.Guid, then
            // the logged in Person.
            if (personGuid.HasValue)
            {
                personAliasId = personAliasService.GetPrimaryAliasId(personGuid.Value);
            }
            else if (personAliasGuid.HasValue)
            {
                personAliasId = personAliasService.GetId(personAliasGuid.Value);
            }
            else
            {
                personAliasId = GetPersonAliasId(rockContext);
            }

            // Verify we have a person alias, otherwise bail out.
            if (!personAliasId.HasValue)
            {
                var errorResponse = Request.CreateErrorResponse(HttpStatusCode.BadRequest, $"The personAliasId could not be determined.");
                throw new HttpResponseException(errorResponse);
            }

            MediaElement mediaElement = null;

            // In the future we might make MediaElementGuid optional so
            // perform the check this way rather than making it required
            // in the parameter list.
            if (mediaElementGuid.HasValue)
            {
                mediaElement = new MediaElementService(rockContext).GetNoTracking(mediaElementGuid.Value);
            }

            // Ensure we have our required MediaElement.
            if (mediaElement == null)
            {
                var errorResponse = Request.CreateErrorResponse(HttpStatusCode.BadRequest, $"The MediaElement could not be found.");
                throw new HttpResponseException(errorResponse);
            }

            // Get (or create) the component.
            var interactionChannelId   = InteractionChannelCache.Get(SystemGuid.InteractionChannel.MEDIA_EVENTS).Id;
            var interactionComponentId = InteractionComponentCache.GetComponentIdByChannelIdAndEntityId(interactionChannelId, mediaElement.Id, mediaElement.Name);

            Interaction interaction = interactionService.Queryable()
                                      .AsNoTracking()
                                      .Include(a => a.PersonAlias)
                                      .Where(a => a.InteractionComponentId == interactionComponentId)
                                      .Where(a => a.PersonAliasId == personAliasId || a.PersonAlias.Person.Aliases.Any(b => b.Id == personAliasId))
                                      .OrderByDescending(a => a.InteractionEndDateTime)
                                      .ThenByDescending(a => a.InteractionDateTime)
                                      .FirstOrDefault();

            if (interaction == null)
            {
                var errorResponse = Request.CreateErrorResponse(HttpStatusCode.NotFound, $"The Interaction could not be found.");
                throw new HttpResponseException(errorResponse);
            }

            var data = interaction.InteractionData.FromJsonOrNull <MediaWatchedInteractionData>();

            return(new MediaElementInteraction
            {
                InteractionGuid = interaction.Guid,
                MediaElementGuid = mediaElement.Guid,
                PersonGuid = interaction.PersonAlias.Person?.Guid,
                PersonAliasGuid = interaction.PersonAlias.Guid,
                RelatedEntityTypeId = interaction.RelatedEntityTypeId,
                RelatedEntityId = interaction.RelatedEntityId,
                WatchMap = data?.WatchMap ?? string.Empty
            });
        }
Esempio n. 11
0
        public MediaElementInteraction PostWatchInteraction(MediaElementInteraction mediaInteraction)
        {
            var rockContext        = Service.Context as RockContext;
            var personService      = new PersonService(rockContext);
            var personAliasService = new PersonAliasService(rockContext);
            var interactionService = new InteractionService(rockContext);
            int?personAliasId;

            if (!IsWatchMapValid(mediaInteraction.WatchMap))
            {
                var errorResponse = Request.CreateErrorResponse(HttpStatusCode.BadRequest, $"The WatchMap contains invalid characters.");
                throw new HttpResponseException(errorResponse);
            }

            // Get the person alias to associate with the interaction in
            // order of provided Person.Guid, then PersonAlias.Guid, then
            // the logged in Person.
            if (mediaInteraction.PersonGuid.HasValue)
            {
                personAliasId = personAliasService.GetPrimaryAliasId(mediaInteraction.PersonGuid.Value);
            }
            else if (mediaInteraction.PersonAliasGuid.HasValue)
            {
                personAliasId = personAliasService.GetId(mediaInteraction.PersonAliasGuid.Value);
            }
            else
            {
                personAliasId = GetPersonAliasId(rockContext);
            }

            var mediaElement = new MediaElementService(rockContext).GetNoTracking(mediaInteraction.MediaElementGuid);

            // Ensure we have our required MediaElement.
            if (mediaElement == null)
            {
                var errorResponse = Request.CreateErrorResponse(HttpStatusCode.BadRequest, $"The MediaElement could not be found.");
                throw new HttpResponseException(errorResponse);
            }

            // Get (or create) the component.
            var         interactionChannelId   = InteractionChannelCache.Get(SystemGuid.InteractionChannel.MEDIA_EVENTS).Id;
            var         interactionComponentId = InteractionComponentCache.GetComponentIdByChannelIdAndEntityId(interactionChannelId, mediaElement.Id, mediaElement.Name);
            Interaction interaction            = null;

            if (mediaInteraction.InteractionGuid.HasValue)
            {
                // Look for an existing Interaction by it's Guid and the
                // component it is supposed to show up under. But also
                // check that the RelatedEntityTypeId/RelatedEntityId values
                // are either null or match what was passed by the user.
                // Finally also make sure the Interaction Person Alias is
                // either the one for this user OR if there is a Person
                // record attached to that alias that the alias Id we have is
                // also attached to that Person record OR the interaction is
                // not tied to a person.
                interaction = interactionService.Queryable()
                              .Where(a => a.Guid == mediaInteraction.InteractionGuid.Value && a.InteractionComponentId == interactionComponentId)
                              .Where(a => !a.RelatedEntityTypeId.HasValue || !mediaInteraction.RelatedEntityTypeId.HasValue || a.RelatedEntityTypeId == mediaInteraction.RelatedEntityTypeId)
                              .Where(a => !a.RelatedEntityId.HasValue || !mediaInteraction.RelatedEntityId.HasValue || a.RelatedEntityId == mediaInteraction.RelatedEntityId)
                              .Where(a => !a.PersonAliasId.HasValue || a.PersonAliasId == personAliasId || a.PersonAlias.Person.Aliases.Any(b => b.Id == personAliasId))
                              .SingleOrDefault();
            }

            var watchedPercentage = CalculateWatchedPercentage(mediaInteraction.WatchMap);

            if (interaction != null)
            {
                // Update the interaction data with the new watch map.
                var data = interaction.InteractionData.FromJsonOrNull <MediaWatchedInteractionData>() ?? new MediaWatchedInteractionData();
                data.WatchMap          = mediaInteraction.WatchMap;
                data.WatchedPercentage = watchedPercentage;

                interaction.InteractionData        = data.ToJson();
                interaction.InteractionLength      = watchedPercentage;
                interaction.InteractionEndDateTime = RockDateTime.Now;
                interaction.PersonAliasId          = interaction.PersonAliasId ?? personAliasId;

                if (mediaInteraction.RelatedEntityTypeId.HasValue)
                {
                    interaction.RelatedEntityTypeId = mediaInteraction.RelatedEntityTypeId;
                }

                if (mediaInteraction.RelatedEntityId.HasValue)
                {
                    interaction.RelatedEntityId = mediaInteraction.RelatedEntityId;
                }
            }
            else
            {
                // Generate the interaction data from the watch map.
                var data = new MediaWatchedInteractionData
                {
                    WatchMap          = mediaInteraction.WatchMap,
                    WatchedPercentage = watchedPercentage
                };

                interaction = interactionService.CreateInteraction(interactionComponentId,
                                                                   null, "Watch", string.Empty, data.ToJson(), personAliasId, RockDateTime.Now,
                                                                   null, null, null, null, null, null);

                interaction.InteractionLength      = watchedPercentage;
                interaction.InteractionEndDateTime = RockDateTime.Now;
                interaction.RelatedEntityTypeId    = mediaInteraction.RelatedEntityTypeId;
                interaction.RelatedEntityId        = mediaInteraction.RelatedEntityId;

                interactionService.Add(interaction);
            }

            rockContext.SaveChanges();

            mediaInteraction.InteractionGuid = interaction.Guid;

            return(mediaInteraction);
        }
Esempio n. 12
0
        public IHttpActionResult PostInteractions([FromBody] List <MobileInteractionSession> sessions, Guid?personalDeviceGuid = null)
        {
            var person    = GetPerson();
            var ipAddress = System.Web.HttpContext.Current?.Request?.UserHostAddress;

            using (var rockContext = new Data.RockContext())
            {
                var interactionChannelService   = new InteractionChannelService(rockContext);
                var interactionComponentService = new InteractionComponentService(rockContext);
                var interactionSessionService   = new InteractionSessionService(rockContext);
                var interactionService          = new InteractionService(rockContext);
                var userLoginService            = new UserLoginService(rockContext);
                var channelMediumTypeValue      = DefinedValueCache.Get(SystemGuid.DefinedValue.INTERACTIONCHANNELTYPE_WEBSITE);
                var pageEntityTypeId            = EntityTypeCache.Get(typeof(Model.Page)).Id;

                //
                // Check to see if we have a site and the API key is valid.
                //
                if (MobileHelper.GetCurrentApplicationSite() == null)
                {
                    return(StatusCode(System.Net.HttpStatusCode.Forbidden));
                }

                //
                // Get the personal device identifier if they provided it's unique identifier.
                //
                int?personalDeviceId = null;
                if (personalDeviceGuid.HasValue)
                {
                    personalDeviceId = new PersonalDeviceService(rockContext).GetId(personalDeviceGuid.Value);
                }

                //
                // Create a quick way to cache data since we have to loop twice.
                //
                var interactionComponentLookup = new Dictionary <string, int>();

                //
                // Helper method to get a cache key for looking up the component Id.
                //
                string GetComponentCacheKey(MobileInteraction mi)
                {
                    return($"{mi.AppId}:{mi.PageGuid}:{mi.ChannelGuid}:{mi.ChannelId}:{mi.ComponentId}:{mi.ComponentName}");
                }

                //
                // Interactions Components will now try to load from cache which
                // causes problems if we are inside a transaction. So first loop through
                // everything and make sure all our components and channels exist.
                //
                var prePassInteractions = sessions.SelectMany(a => a.Interactions)
                                          .DistinctBy(a => GetComponentCacheKey(a));

                //
                // It's safe to do this pre-pass outside the transaction since we are just creating
                // the channels and components (if necessary), which is going to have to be done at
                // at some point no matter what.
                //
                foreach (var mobileInteraction in prePassInteractions)
                {
                    //
                    // Lookup the interaction channel, and create it if it doesn't exist
                    //
                    if (mobileInteraction.AppId.HasValue && mobileInteraction.PageGuid.HasValue)
                    {
                        var site = SiteCache.Get(mobileInteraction.AppId.Value);
                        var page = PageCache.Get(mobileInteraction.PageGuid.Value);

                        if (site == null || page == null)
                        {
                            continue;
                        }

                        //
                        // Try to find an existing interaction channel.
                        //
                        var interactionChannelId = InteractionChannelCache.GetChannelIdByTypeIdAndEntityId(channelMediumTypeValue.Id, site.Id, site.Name, pageEntityTypeId, null);

                        //
                        // Get an existing or create a new component.
                        //
                        var interactionComponentId = InteractionComponentCache.GetComponentIdByChannelIdAndEntityId(interactionChannelId, page.Id, page.InternalName);

                        interactionComponentLookup.AddOrReplace(GetComponentCacheKey(mobileInteraction), interactionComponentId);
                    }
                    else if (mobileInteraction.ChannelId.HasValue || mobileInteraction.ChannelGuid.HasValue)
                    {
                        int?interactionChannelId = null;

                        if (mobileInteraction.ChannelId.HasValue)
                        {
                            interactionChannelId = mobileInteraction.ChannelId.Value;
                        }
                        else if (mobileInteraction.ChannelGuid.HasValue)
                        {
                            interactionChannelId = InteractionChannelCache.Get(mobileInteraction.ChannelGuid.Value)?.Id;
                        }

                        if (interactionChannelId.HasValue)
                        {
                            if (mobileInteraction.ComponentId.HasValue)
                            {
                                // Use the provided component identifier.
                                interactionComponentLookup.AddOrReplace(GetComponentCacheKey(mobileInteraction), mobileInteraction.ComponentId.Value);
                            }
                            else if (mobileInteraction.ComponentName.IsNotNullOrWhiteSpace())
                            {
                                int interactionComponentId;

                                // Get or create a new component with the details we have.
                                if (mobileInteraction.ComponentEntityId.HasValue)
                                {
                                    interactionComponentId = InteractionComponentCache.GetComponentIdByChannelIdAndEntityId(interactionChannelId.Value, mobileInteraction.ComponentEntityId, mobileInteraction.ComponentName);
                                }
                                else
                                {
                                    var interactionComponent = interactionComponentService.GetComponentByComponentName(interactionChannelId.Value, mobileInteraction.ComponentName);

                                    rockContext.SaveChanges();

                                    interactionComponentId = interactionComponent.Id;
                                }

                                interactionComponentLookup.AddOrReplace(GetComponentCacheKey(mobileInteraction), interactionComponentId);
                            }
                        }
                    }
                }

                //
                // Now wrap the actual interaction creation inside a transaction. We should
                // probably move this so it uses the InteractionTransaction class for better
                // performance. This is so we can inform the client that either everything
                // saved or that nothing saved. No partial saves here.
                //
                rockContext.WrapTransaction(() =>
                {
                    foreach (var mobileSession in sessions)
                    {
                        var interactionGuids         = mobileSession.Interactions.Select(i => i.Guid).ToList();
                        var existingInteractionGuids = interactionService.Queryable()
                                                       .Where(i => interactionGuids.Contains(i.Guid))
                                                       .Select(i => i.Guid)
                                                       .ToList();

                        //
                        // Loop through all interactions that don't already exist and add each one.
                        //
                        foreach (var mobileInteraction in mobileSession.Interactions.Where(i => !existingInteractionGuids.Contains(i.Guid)))
                        {
                            string cacheKey = GetComponentCacheKey(mobileInteraction);

                            if (!interactionComponentLookup.ContainsKey(cacheKey))
                            {
                                // Shouldn't happen, but just in case.
                                continue;
                            }

                            var interactionComponentId = interactionComponentLookup[cacheKey];

                            //
                            // Add the interaction
                            //
                            var interaction = interactionService.CreateInteraction(interactionComponentId,
                                                                                   mobileInteraction.EntityId,
                                                                                   mobileInteraction.Operation,
                                                                                   mobileInteraction.Summary,
                                                                                   mobileInteraction.Data,
                                                                                   person?.PrimaryAliasId,
                                                                                   RockDateTime.ConvertLocalDateTimeToRockDateTime(mobileInteraction.DateTime.LocalDateTime),
                                                                                   mobileSession.Application,
                                                                                   mobileSession.OperatingSystem,
                                                                                   mobileSession.ClientType,
                                                                                   null,
                                                                                   ipAddress,
                                                                                   mobileSession.Guid);

                            interaction.Guid                  = mobileInteraction.Guid;
                            interaction.PersonalDeviceId      = personalDeviceId;
                            interaction.RelatedEntityTypeId   = mobileInteraction.RelatedEntityTypeId;
                            interaction.RelatedEntityId       = mobileInteraction.RelatedEntityId;
                            interaction.ChannelCustom1        = mobileInteraction.ChannelCustom1;
                            interaction.ChannelCustom2        = mobileInteraction.ChannelCustom2;
                            interaction.ChannelCustomIndexed1 = mobileInteraction.ChannelCustomIndexed1;

                            interactionService.Add(interaction);

                            // Attempt to process this as a communication interaction.
                            ProcessCommunicationInteraction(mobileSession, mobileInteraction, rockContext);
                        }
                    }

                    rockContext.SaveChanges();
                });
            }

            return(Ok());
        }
        /// <summary>
        /// Gets the interaction component cache.
        /// </summary>
        /// <param name="achievementTypeCache">The achievement type cache.</param>
        /// <returns></returns>
        private InteractionComponentCache GetInteractionComponentCache(AchievementTypeCache achievementTypeCache)
        {
            var guid = GetInteractionComponentGuid(achievementTypeCache);

            return(guid.HasValue ? InteractionComponentCache.Get(guid.Value) : null);
        }