Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion Application/GrpcClients/CommonRelationshipClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ public async Task<IList<string>> GetAllBlockerIds(string profileId)
throw new BaseException(BaseError.RELATIONSHIP_NOT_FOUND, StatusCodes.Status404NotFound);
}
}

public async Task<IList<string>> GetAllBlockeeIds(string profileId)
{
try
Expand All @@ -237,6 +237,24 @@ public async Task<IList<string>> GetAllBlockeeIds(string profileId)
throw new BaseException(BaseError.RELATIONSHIP_NOT_FOUND, StatusCodes.Status404NotFound);
}
}
public async Task<IList<ProfileIdWithMutualCount>> GetFriendsOfMutualFriends(string profileId)
{
try
{
logger.LogInformation("Starting get mutual friend list");
var response = await client.getFriendsOfMutualFriendsAsync(new ProfileRequest
{
Id = profileId
});
// Call the gRPC server to introspect the token
return response.ProfileIdsWithMutualCounts;
}
catch (Exception e)
{
logger.LogError(e.Message);
throw new BaseException(BaseError.RELATIONSHIP_NOT_FOUND, StatusCodes.Status404NotFound);
}
}
public async Task<IList<ProfileIdWithMutualCount>> CountMutualFriends(string profileId, IList<string> profileIds)
{
try
Expand Down
2 changes: 2 additions & 0 deletions Application/Protos/relationship.proto
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ service RelationshipService {

rpc countMutualFriends(MutualFriendCountRequest) returns (MutualFriendCountResponse) {}

rpc getFriendsOfMutualFriends(ProfileRequest) returns (MutualFriendCountResponse) {}

rpc getAllPendingRequestIds(ProfileRequest) returns (ProfileIdsResponse) {}

rpc getAllRequestIds(ProfileRequest) returns (ProfileIdsResponse) {}
Expand Down
2 changes: 2 additions & 0 deletions Profile.Application/IServices/IUserProfileService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public interface IUserProfileService

public Task<UserProfile> Update(UserProfile userProfile);

public Task<CursorPagedResult<UserProfile>> SearchFriend(string keyword, string profileId, string cursor, int limit);

public Task<CursorPagedResult<UserProfile>> GetFriendSuggestions(string profileId, string cursor, int limit);

public Task<CursorPagedResult<UserProfile>> GetFriendRequests(string profileId, string cursor, int limit);
Expand Down
37 changes: 30 additions & 7 deletions Profile.Application/Services/UserProfileService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,26 +166,49 @@ public async Task<CursorPagedResult<UserProfile>> GetFriendSentRequests(string p

public async Task<CursorPagedResult<UserProfile>> GetFriendSuggestions(string profileId, string cursor, int limit)
{
IList<string> followeeIds = await relationshipClient.GetAllFolloweeIds(profileId);
IList<string> friendIds = await relationshipClient.GetAllFriendIds(profileId);
//IList<string> followeeIds = await relationshipClient.GetAllFolloweeIds(profileId);
//IList<string> friendIds = await relationshipClient.GetAllFriendIds(profileId);
var friendsOfMutualFriends = await relationshipClient.GetFriendsOfMutualFriends(profileId);
IList<string> pendingRequests = await relationshipClient.GetAllPendingRequestIds(profileId);
IList<string> blockerIds = await relationshipClient.GetAllBlockerIds(profileId.ToString());
IList<string> blockeeIds = await relationshipClient.GetAllBlockeeIds(profileId.ToString());
var mutualFriendIds = friendsOfMutualFriends
.Select(item => item.ProfileId)
.ToList();

var specification = new SpecificationWithCursor<UserProfile>
{
Criteria = userProfile =>
!userProfile.Id.Equals(Guid.Parse(profileId))
&& !friendIds.Contains(userProfile.Id.ToString())
&& !pendingRequests.Contains(userProfile.Id.ToString())
&& !blockerIds.Concat(blockeeIds).Contains(userProfile.Id.ToString())
&& !blockerIds.Concat(blockeeIds).Contains(userProfile.Id.ToString()),
mutualFriendIds.Contains(userProfile.Id.ToString())
& !userProfile.Id.Equals(Guid.Parse(profileId))
//&& !friendIds.Contains(userProfile.Id.ToString())
& !pendingRequests.Contains(userProfile.Id.ToString())
& !blockerIds.Concat(blockeeIds).Contains(userProfile.Id.ToString())
& !blockerIds.Concat(blockeeIds).Contains(userProfile.Id.ToString()),
Cursor = cursor,
Limit = limit
};
return await userProfileRepository.GetPagedAsync(specification);
}
public async Task<CursorPagedResult<UserProfile>> SearchFriend(string keywords, string profileId, string cursor, int limit)
{

IList<string> blockerIds = await relationshipClient.GetAllBlockerIds(profileId.ToString());
IList<string> blockeeIds = await relationshipClient.GetAllBlockeeIds(profileId.ToString());

var specification = new SpecificationWithCursor<UserProfile>
{
Criteria = userProfile =>
(string.IsNullOrEmpty(keywords) ||
userProfile.FirstName.Contains(keywords, StringComparison.CurrentCultureIgnoreCase) ||
userProfile.LastName.Contains(keywords, StringComparison.CurrentCultureIgnoreCase) ||
userProfile.Username.Contains(keywords, StringComparison.CurrentCultureIgnoreCase))
&!blockerIds.Concat(blockeeIds).Contains(userProfile.Id.ToString()),
Cursor = cursor,
Limit = limit
};
return await userProfileRepository.GetPagedAsync(specification);
}
public async Task<UserProfile> GetByAccountId(string id)
=> await userProfileRepository.GetByAccountIdAsync(Guid.Parse(id));

Expand Down
54 changes: 54 additions & 0 deletions Profile.Presentation/Controllers/FriendController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,60 @@ public async Task<IActionResult> GetFriendSuggestions([FromQuery] string nextCur
});
}

[EndpointDescription("Retrieve friend suggestions")]
[ProducesResponseType(typeof(CursorPagedResult<FriendshipResponse>), StatusCodes.Status200OK)]
[Authorize]
[HttpGet("search")]
public async Task<IActionResult> SearchFriends([FromQuery] string nextCursor, [FromQuery] int limit = 10)
{
string currentProfileId = GetCurrentProfileId != null ? GetCurrentProfileId().ToString()
: throw new BaseException(BaseError.PROFILE_NOT_FOUND, StatusCodes.Status404NotFound);

var suggestions = await userProfileService.GetFriendSuggestions(currentProfileId, nextCursor, limit);

var photoMetadataIds = suggestions.Items
.Where(profile => profile.AvatarId != null)
.Select(profile => profile.AvatarId)
.Distinct();

var photoMetadataTasks = photoMetadataIds.Select(async id =>
{
var metadata = await fileClient.GetPhotoMetadata(id.ToString());
return new { Id = id, Metadata = metadata ??= new PhotoMetadataResponse { Id = id.Value } };
});
var photoMetadataDict = (await Task.WhenAll(photoMetadataTasks)).ToDictionary(x => x.Id, x => x.Metadata);

var resultHasCount = await relationshipClient
.CountMutualFriends(currentProfileId, suggestions.Items.Select(f => f.Id.ToString()).ToList());

var resultHasCountDict = resultHasCount.ToDictionary(p => p.ProfileId);

IList<FriendshipResponse> result = [];
foreach (var item in suggestions.Items)
{
var userProfile = mapper.Map<UserProfileResponse>(item);
if (userProfile.Avatar != null)
{
if (photoMetadataDict.TryGetValue(item.AvatarId, out var avatar))
{
userProfile.Avatar = avatar;
}
}

var itemResponse = mapper.Map<FriendshipResponse>(userProfile);
itemResponse.Status = "NotConnected";
if (resultHasCountDict.TryGetValue(item.Id.ToString(), out var rs))
if (rs.Count > 0) itemResponse.MutualFriendsCount = rs.Count;

result.Add(itemResponse);
}

return Ok(new CursorPagedResult<FriendshipResponse>()
{
Items = result,
NextCursor = suggestions.NextCursor
});
}
//[EndpointDescription("Retrieve requests")]
//[ProducesResponseType(typeof(CursorPagedResult<FriendSuggestionResponse>), StatusCodes.Status200OK)]
//[Authorize]
Expand Down
11 changes: 9 additions & 2 deletions Relationship.Application/GrpcServices/GrpcRelationshipService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public override async Task<ProfileIdsResponse> getAllBlockerIds(ProfileRequest r
response.Ids.AddRange(source);
return response;
}

public override async Task<ProfileIdsResponse> getAllBlockeeIds(ProfileRequest request, ServerCallContext context)
{
logger.LogInformation("Get blockees for ProfileId: {ProfileId}", request.Id);
Expand All @@ -132,7 +132,14 @@ public override async Task<ProfileIdsResponse> getAllBlockeeIds(ProfileRequest r
response.Ids.AddRange(source);
return response;
}

public override async Task<MutualFriendCountResponse> getFriendsOfMutualFriends(ProfileRequest request, ServerCallContext context)
{
logger.LogInformation("Get mutual friend count for ProfileId: {ProfileId}", request.Id);
var source = await friendshipService.GetAllMutualFriendsWithCount(request.Id);
var response = new MutualFriendCountResponse();
response.ProfileIdsWithMutualCounts.AddRange(source.Select(mapper.Map<ProfileIdWithMutualCount>));
return response;
}
public override async Task<MutualFriendCountResponse> countMutualFriends(MutualFriendCountRequest request, ServerCallContext context)
{
logger.LogInformation("Get mutual friend count for ProfileId: {ProfileId}", request.CurrentProfileId);
Expand Down
4 changes: 4 additions & 0 deletions Relationship.Application/IServices/IFriendshipService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ public interface IFriendshipService

public Task<IList<string>> GetAllPendingRequestIds(string profile);

public Task<IList<string>> GetAllMutualFriendIds(string profile);

public Task<IList<ProfileIdWithMutualCount>> GetAllMutualFriendsWithCount(string profile);

public Task<IList<string>> GetAllRequestIds(string profile);

public Task<IList<string>> GetAllSentRequestIds(string profile);
Expand Down
22 changes: 19 additions & 3 deletions Relationship.Application/Services/FriendshipService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,11 @@ public async Task<IList<string>> GetAllPendingRequestIds(string profileId)

public async Task<IList<ProfileIdWithMutualCount>> CountMutualFriends(string currentProfileId, IList<string> profileIds)
{
var list = await friendshipRepository.CountMutualFriends(profileIds, Guid.Parse(currentProfileId));
return list.Select(item => new ProfileIdWithMutualCount
var list = profileIds.Select(x => Guid.Parse(x)).ToList();
var friendsOfMutualFriends = await friendshipRepository.GetMutualFriendsAndCount(Guid.Parse(currentProfileId), list);
return friendsOfMutualFriends.Select(item => new ProfileIdWithMutualCount
{
ProfileId = item.FriendId.ToString(),
ProfileId = item.MutualFriendId.ToString(),
Count = item.MutualFriendCount
}).ToList();
}
Expand Down Expand Up @@ -271,6 +272,21 @@ private async Task PublishFriendshipNotificationCommands(Friendship entity)

await messageBus.Publish(notificationCommand);
}
public async Task<IList<ProfileIdWithMutualCount>> GetAllMutualFriendsWithCount(string profile)
{

var list = await friendshipRepository.GetFriendsOfMutualFriend(Guid.Parse(profile));
var friendsOfMutualFriends = await friendshipRepository.GetMutualFriendsAndCount(Guid.Parse(profile), list);
return friendsOfMutualFriends.Select(item => new ProfileIdWithMutualCount
{
ProfileId = item.MutualFriendId.ToString(),
Count = item.MutualFriendCount
}).ToList();
}

public Task<IList<string>> GetAllMutualFriendIds(string profile)
{
throw new NotImplementedException();
}
}
}
6 changes: 4 additions & 2 deletions Relationship.Domain/Repositories/IFriendshipRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ public interface IFriendshipRepository : ISqlRepository<Friendship, Guid>

Task<int> CountMutualFriends(Guid profileId, Guid currentProfile);

Task<IList<Guid>> GetAllFriendIdsOfCurrentUserAsync(Guid currentUserId);

Task<IList<Guid>> GetAllMutualFriendIdsAsync(Guid currentUserId, IList<Guid> friendsOfCurrentUser);

Task<IList<(Guid MutualFriendId, int MutualFriendCount)>> GetMutualFriendsAndCount(Guid currentUserId, IList<Guid> friendsOfMutualFriend);

Task<IList<Guid>> GetFriendsOfMutualFriend(Guid currentUserId);

Task<IList<(Guid FriendId, int MutualFriendCount)>> CountMutualFriends(IList<string> results, Guid currentUserId);

Task<IList<Guid>> GetAllRequestIdsAsync(Guid currentUserId);
Expand Down
77 changes: 58 additions & 19 deletions Relationship.Infrastructure/Repositories/FriendshipRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,48 @@ public async Task<IList<Guid>> GetAllMutualFriendIdsAsync(Guid currentUserId, IL
.Distinct()
.ToListAsync();
}
public async Task<IList<Guid>> GetAllFriendIdsOfCurrentUserAsync(Guid currentUserId)

public async Task<IList<Guid>> GetFriendsOfMutualFriend(Guid currentUserId)
{
return await context.Friendships
.Where(f => (f.SenderId == currentUserId || f.ReceiverId == currentUserId) && f.Status == FriendshipStatus.Connected )
.Select(f => f.SenderId == currentUserId ? f.ReceiverId : f.SenderId)
var friendsOfUser = await DbSet
.Where(f1 => (f1.SenderId == currentUserId || f1.ReceiverId == currentUserId) && f1.Status == FriendshipStatus.Connected)
.Select(f1 => f1.SenderId == currentUserId ? f1.ReceiverId : f1.SenderId)
.ToListAsync();

var mutualFriends = await DbSet
.Where(f2 => friendsOfUser.Contains(f2.SenderId) || friendsOfUser.Contains(f2.ReceiverId))
.Where(f2 => f2.Status == FriendshipStatus.Connected && f2.SenderId != currentUserId && f2.ReceiverId != currentUserId)
.Select(f2 => friendsOfUser.Contains(f2.SenderId) ? f2.ReceiverId : f2.SenderId)
.Distinct()
.ToListAsync();

return mutualFriends;
}

public int GetMutualFriendCount(IList<Guid> currentUserFiends, IList<Guid> friendOfFriends)
{
var mutualFriends = currentUserFiends.Intersect(friendOfFriends).ToList();

int mutualFriendCount = mutualFriends.Count;

return mutualFriendCount;
}

public async Task<IList<(Guid MutualFriendId, int MutualFriendCount)>> GetMutualFriendsAndCount(Guid currentUserId, IList<Guid> friendsOfMutualFriend)
{
var friendsOfUser = await GetAllFriendIdsAsync(currentUserId);

var friendsOfMutualFriendAndCount = new List<(Guid MutualFriendId, int MutualFriendCount)>();

foreach (var friend in friendsOfMutualFriend)
{
var mutualFriendFriends = await GetAllFriendIdsAsync(friend);

var mutualFriendCount = GetMutualFriendCount(friendsOfUser, mutualFriendFriends);

friendsOfMutualFriendAndCount.Add((MutualFriendId: friend, MutualFriendCount: mutualFriendCount));
}
return friendsOfMutualFriendAndCount;
}

public async Task<IList<Guid>> GetAllPendingRequestIdsAsync(Guid currentUserId)
Expand All @@ -93,22 +128,26 @@ public async Task<IList<Guid>> GetAllSentRequestIdsAsync(Guid currentUserId)
.ToListAsync();
}

public async Task<IList<(Guid FriendId, int MutualFriendCount)>> CountMutualFriends(IList<string> results, Guid currentUserId)
public async Task<IList<(Guid FriendId, int MutualFriendCount)>> CountMutualFriends(IList<string> friendIds, Guid currentUserId)
{
var resultGuids = results.Select(Guid.Parse).ToList();
var queryResult = await context.Friendships
.Where(f => resultGuids.Contains(f.SenderId) || resultGuids.Contains(f.ReceiverId))
.Where(f => f.SenderId != currentUserId && f.ReceiverId != currentUserId)
.Select(f => f.SenderId == currentUserId ? f.ReceiverId : f.SenderId)
.GroupBy(friendId => friendId)
.Select(group => new
{
FriendId = group.Key,
Count = group.Count()
})
.ToListAsync();
var mutualFriendCounts = await context.Friendships
.Where(f1 => (f1.SenderId == currentUserId || f1.ReceiverId == currentUserId) && f1.Status == FriendshipStatus.Connected)
.Join(
context.Friendships,
f1 => f1.SenderId == currentUserId ? f1.ReceiverId : f1.SenderId,
f2 => f2.SenderId == currentUserId ? f2.ReceiverId : f2.SenderId,
(f1, f2) => new { FriendA = f1.SenderId == currentUserId ? f1.ReceiverId : f1.SenderId, FriendB = f2.SenderId == currentUserId ? f2.ReceiverId : f2.SenderId }
)
.Where(match => friendIds.Contains(match.FriendB.ToString()))
.GroupBy(match => match.FriendB)
.Select(group => new
{
FriendId = group.Key,
MutualFriendCount = group.Count()
})
.ToListAsync();

return queryResult.Select(x => (x.FriendId, x.Count)).ToList();
return mutualFriendCounts.Select(x => (x.FriendId, x.MutualFriendCount)).ToList();
}

}
Expand Down
9 changes: 5 additions & 4 deletions Relationship.Presentation/Controllers/FriendshipController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,8 @@ public async Task<IActionResult> GetFriends([FromQuery] string nextCursor, [From
var friends = await friendshipService.GetFriends(currentProfileId, nextCursor, limit);

// Tập hợp toàn bộ các ID cần nạp trước
var profileIds = friends.Items.Select(item => item.SenderId.ToString()).Distinct();
profileIds.ToList().Add(currentProfileId);
var profileIds = friends.Items.Select(item => currentProfileId.Equals(item.SenderId.ToString()) ? item.ReceiverId.ToString() : item.SenderId.ToString()).Distinct();
//profileIds.ToList().Add(currentProfileId);

// Nạp toàn bộ profiles cần thiết
var profiles = await commonProfileClient.GetProfiles(profileIds.ToList());
Expand All @@ -222,14 +222,15 @@ public async Task<IActionResult> GetFriends([FromQuery] string nextCursor, [From
});
var photoMetadataDict = (await Task.WhenAll(photoMetadataTasks)).ToDictionary(x => x.Id, x => x.Metadata);

var resultHasCount = await friendshipService.CountMutualFriends(currentProfileId, friends.Items.Select(f => f.SenderId.ToString()).ToList());
var resultHasCount = await friendshipService.CountMutualFriends(currentProfileId, friends.Items.Select(f => currentProfileId.Equals(f.SenderId.ToString()) ? f.ReceiverId.ToString() : f.SenderId.ToString()).ToList());

var resultHasCountDict = resultHasCount.ToDictionary(p => p.ProfileId);

IList<FriendshipResponse> result = [];
foreach (var item in friends.Items)
{
if (profileDict.TryGetValue(item.SenderId, out var profile))
var profileId = currentProfileId.Equals(item.SenderId.ToString()) ? item.ReceiverId : item.SenderId;
if (profileDict.TryGetValue(profileId, out var profile))
{
if (profile.Avatar != null)
{
Expand Down
Loading