Ejemplo n.º 1
0
        /// <summary>
        /// Update a relationship between a user and a topic
        /// </summary>
        /// <param name="processType">Process type</param>
        /// <param name="relationshipOperation">Relationship operation</param>
        /// <param name="relationshipHandle">Relationship handle</param>
        /// <param name="followerUserHandle">Follower user handle</param>
        /// <param name="followingTopicHandle">Following topic handle</param>
        /// <param name="appHandle">App handle</param>
        /// <param name="lastUpdatedTime">Last updated time</param>
        /// <param name="followerRelationshipLookupEntity">Follower relationship lookup entity</param>
        /// <param name="followingRelationshipLookupEntity">Following relationship lookup entity</param>
        /// <returns>Update relationship task</returns>
        public async Task UpdateRelationshipToTopic(
            ProcessType processType,
            RelationshipOperation relationshipOperation,
            string relationshipHandle,
            string followerUserHandle,
            string followingTopicHandle,
            string appHandle,
            DateTime lastUpdatedTime,
            ITopicRelationshipLookupEntity followerRelationshipLookupEntity,
            ITopicRelationshipLookupEntity followingRelationshipLookupEntity)
        {
            TopicRelationshipStatus topicRelationshipStatus = this.GetTopicRelationshipStatus(relationshipOperation);

            if (processType == ProcessType.Frontend)
            {
                await this.topicRelationshipsStore.UpdateTopicFollowerRelationship(
                    StorageConsistencyMode.Strong,
                    relationshipHandle,
                    followingTopicHandle,
                    followerUserHandle,
                    appHandle,
                    topicRelationshipStatus,
                    lastUpdatedTime,
                    followerRelationshipLookupEntity);

                await this.topicRelationshipsStore.UpdateTopicFollowingRelationship(
                    StorageConsistencyMode.Strong,
                    relationshipHandle,
                    followerUserHandle,
                    followingTopicHandle,
                    appHandle,
                    topicRelationshipStatus,
                    lastUpdatedTime,
                    followingRelationshipLookupEntity);

                // fanout an activity indicating that the followerUser is now following the followingTopicHandle
                await this.fanoutActivitiesQueue.SendFanoutActivityMessage(
                    followerUserHandle,
                    appHandle,
                    relationshipHandle,
                    ActivityType.Following,
                    followerUserHandle,
                    null,
                    ContentType.Topic,
                    followingTopicHandle,
                    lastUpdatedTime);
            }
        }
        /// <summary>
        /// Update a relationship with a topic
        /// </summary>
        /// <param name="callerClassName">name of the controller class of the caller</param>
        /// <param name="callerMethodName">name of method insider controller class of the caller (should correspond to an HTTP action)</param>
        /// <param name="relationshipOperation">Relationship operation</param>
        /// <param name="actedOnTopicHandle">Acted on topic handle</param>
        /// <returns>No content on success</returns>
        protected async Task <IHttpActionResult> UpdateRelationshipToTopic(
            string callerClassName,
            string callerMethodName,
            RelationshipOperation relationshipOperation,
            string actedOnTopicHandle)
        {
            string   actorUserHandle = this.UserHandle;
            DateTime currentTime     = DateTime.UtcNow;

            if (relationshipOperation != RelationshipOperation.FollowTopic && relationshipOperation != RelationshipOperation.UnfollowTopic)
            {
                // the caller should never specify a operation other than FollowTopic or UnfollowTopic
                return(this.InternalServerError());
            }

            // get the topic being followed
            TopicView topicView = await this.viewsManager.GetTopicView(actedOnTopicHandle, actorUserHandle);

            if (topicView == null)
            {
                // This could mean one of three situations:
                // (1) the topic has been banned and hence is no longer accessible to anyone,
                // (2) the topic has been deleted,
                // (3) the topic is from a private user that the actor user is not following; this should
                //     not happen because the actor user should not be able to get a topicHandle for a topic
                //     posted by a private user that they are not following
                return(this.NotFound(ResponseStrings.TopicNotFound));
            }

            // lookup the existing relationships
            ITopicRelationshipLookupEntity followerRelationshipLookupEntity
                = await this.relationshipsManager.ReadTopicFollowerRelationship(actedOnTopicHandle, actorUserHandle, this.AppHandle);

            if (followerRelationshipLookupEntity != null && followerRelationshipLookupEntity.LastUpdatedTime > currentTime)
            {
                // this relationship has been updated more recently than this request
                return(this.Conflict(ResponseStrings.NewerItemExists));
            }

            ITopicRelationshipLookupEntity followingRelationshipLookupEntity =
                await this.relationshipsManager.ReadFollowingRelationshipToTopic(actorUserHandle, actedOnTopicHandle, this.AppHandle);

            if (followingRelationshipLookupEntity != null && followingRelationshipLookupEntity.LastUpdatedTime > currentTime)
            {
                // this relationship has been updated more recently than this request
                return(this.Conflict(ResponseStrings.NewerItemExists));
            }

            // if following a topic
            string relationshipHandle = null;

            if (relationshipOperation == RelationshipOperation.FollowTopic)
            {
                // create a relationship handle
                relationshipHandle = this.handleGenerator.GenerateShortHandle();

                // insert the topic into the user's following topic feed
                await this.topicsManager.CreateFollowingTopic(actorUserHandle, this.AppHandle, actedOnTopicHandle);
            }

            if (relationshipOperation == RelationshipOperation.UnfollowTopic)
            {
                try
                {
                    // remove the topic from the user's following topic feed
                    await this.topicsManager.DeleteFollowingTopic(actorUserHandle, this.AppHandle, actedOnTopicHandle);
                }
                catch (NotFoundException)
                {
                    return(this.NotFound(ResponseStrings.NotFollowingTopic));
                }
            }

            // submit the request to the relationship manager
            await this.relationshipsManager.UpdateRelationshipToTopic(
                ProcessType.Frontend,
                relationshipOperation,
                relationshipHandle,
                actorUserHandle,
                actedOnTopicHandle,
                this.AppHandle,
                currentTime,
                followerRelationshipLookupEntity,
                followingRelationshipLookupEntity);

            string logEntry = $"TopicHandle = {topicView?.TopicHandle}, RelationshipHandle = {relationshipHandle}, RelationshipOperation = {relationshipOperation.ToString()}";

            this.LogControllerEnd(this.log, callerClassName, callerMethodName, logEntry);

            return(this.NoContent());
        }
        /// <summary>
        /// Update topic follower relationship.
        /// Follower user : someone who follows the topic.
        /// </summary>
        /// <param name="storageConsistencyMode">Consistency mode</param>
        /// <param name="relationshipHandle">Relationship handle</param>
        /// <param name="topicHandle">topic handle</param>
        /// <param name="relationshipUserHandle">Relationship user handle</param>
        /// <param name="appHandle">App handle</param>
        /// <param name="topicRelationshipStatus">Topic relationship status</param>
        /// <param name="lastUpdatedTime">Last updated time</param>
        /// <param name="readTopicRelationshipLookupEntity">Read topic relationship lookup entity</param>
        /// <returns>Update follower relationship task</returns>
        public async Task UpdateTopicFollowerRelationship(
            StorageConsistencyMode storageConsistencyMode,
            string relationshipHandle,
            string topicHandle,
            string relationshipUserHandle,
            string appHandle,
            TopicRelationshipStatus topicRelationshipStatus,
            DateTime lastUpdatedTime,
            ITopicRelationshipLookupEntity readTopicRelationshipLookupEntity)
        {
            CTStore store = await this.tableStoreManager.GetStore(ContainerIdentifier.TopicFollowers);

            ObjectTable lookupTable = this.tableStoreManager.GetTable(ContainerIdentifier.TopicFollowers, TableIdentifier.TopicFollowersLookup) as ObjectTable;
            FeedTable   feedTable   = this.tableStoreManager.GetTable(ContainerIdentifier.TopicFollowers, TableIdentifier.TopicFollowersFeed) as FeedTable;
            CountTable  countTable  = this.tableStoreManager.GetTable(ContainerIdentifier.TopicFollowers, TableIdentifier.TopicFollowersCount) as CountTable;

            string objectKey = this.GetObjectKey(appHandle, relationshipUserHandle);
            string feedKey   = this.GetFeedKey(appHandle, topicRelationshipStatus);
            string countKey  = this.GetCountKey(appHandle, topicRelationshipStatus);

            Transaction transaction = new Transaction();

            UserRelationshipFeedEntity relationshipFeedEntity = new UserRelationshipFeedEntity()
            {
                RelationshipHandle = relationshipHandle,
                UserHandle         = relationshipUserHandle
            };

            if (readTopicRelationshipLookupEntity == null)
            {
                // if readTopicRelationshipLookupEntity is null, then we are inserting a new relationship
                TopicRelationshipLookupEntity newRelationshipLookupEntity = new TopicRelationshipLookupEntity()
                {
                    RelationshipHandle      = relationshipHandle,
                    LastUpdatedTime         = lastUpdatedTime,
                    TopicRelationshipStatus = topicRelationshipStatus,
                };

                transaction.Add(Operation.Insert(lookupTable, topicHandle, objectKey, newRelationshipLookupEntity));

                if (topicRelationshipStatus != TopicRelationshipStatus.None)
                {
                    transaction.Add(Operation.Insert(feedTable, topicHandle, feedKey, relationshipHandle, relationshipFeedEntity));
                    transaction.Add(Operation.InsertOrIncrement(countTable, topicHandle, countKey));
                }
            }
            else
            {
                // otherwise, we are updating an existing relationship
                TopicRelationshipStatus oldTopicRelationshipStatus = readTopicRelationshipLookupEntity.TopicRelationshipStatus;
                string oldRelationshipHandle = readTopicRelationshipLookupEntity.RelationshipHandle;
                string oldFeedKey            = this.GetFeedKey(appHandle, oldTopicRelationshipStatus);
                string oldCountKey           = this.GetCountKey(appHandle, oldTopicRelationshipStatus);

                readTopicRelationshipLookupEntity.RelationshipHandle      = relationshipHandle;
                readTopicRelationshipLookupEntity.TopicRelationshipStatus = topicRelationshipStatus;
                readTopicRelationshipLookupEntity.LastUpdatedTime         = lastUpdatedTime;

                transaction.Add(Operation.Replace(lookupTable, topicHandle, objectKey, readTopicRelationshipLookupEntity as TopicRelationshipLookupEntity));

                if (topicRelationshipStatus == oldTopicRelationshipStatus)
                {
                    if (topicRelationshipStatus != TopicRelationshipStatus.None && relationshipHandle != oldRelationshipHandle)
                    {
                        transaction.Add(Operation.Delete(feedTable, topicHandle, oldFeedKey, oldRelationshipHandle));
                        transaction.Add(Operation.Insert(feedTable, topicHandle, feedKey, relationshipHandle, relationshipFeedEntity));
                    }
                }
                else
                {
                    if (topicRelationshipStatus != TopicRelationshipStatus.None)
                    {
                        transaction.Add(Operation.Insert(feedTable, topicHandle, feedKey, relationshipHandle, relationshipFeedEntity));
                        transaction.Add(Operation.Increment(countTable, topicHandle, countKey));
                    }

                    if (oldTopicRelationshipStatus != TopicRelationshipStatus.None)
                    {
                        transaction.Add(Operation.Delete(feedTable, topicHandle, oldFeedKey, oldRelationshipHandle));
                        transaction.Add(Operation.Increment(countTable, topicHandle, oldCountKey, -1.0));
                    }
                }
            }

            await store.ExecuteTransactionAsync(transaction, storageConsistencyMode.ToConsistencyMode());
        }