/// <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()); }