Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

20 fix get suggestion #22

Merged
merged 4 commits into from
Dec 9, 2024
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
64 changes: 12 additions & 52 deletions Infrastructure/PostgreSQL/Repositories/SqlRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,83 +112,43 @@ public async Task<PagedResult<TEntity>> GetPagedAsync(ISqlSpecification<TEntity>

public async Task<CursorPagedResult<TEntity>> GetPagedAsync(SpecificationWithCursor<TEntity> spec)
{
// Truy vấn cơ bản
var query = context.Set<TEntity>().AsQueryable();

// Áp dụng các điều kiện lọc nếu có
if (spec.Criteria != null)
query = query.Where(spec.Criteria);

// Áp dụng sắp xếp
if (spec.OrderFields == null || !spec.OrderFields.Any())
{
query = query.OrderByDescending(x => x.CreatedAt).ThenByDescending(x => x.Id); // Mặc định
}
else
{
var isFirstField = true;
foreach (var orderField in spec.OrderFields)
{
query = isFirstField
? (orderField.Direction == SortDirection.Descending
? query.OrderByDescending(orderField.Field)
: query.OrderBy(orderField.Field))
: (orderField.Direction == SortDirection.Descending
? ((IOrderedQueryable<TEntity>)query).ThenByDescending(orderField.Field)
: ((IOrderedQueryable<TEntity>)query).ThenBy(orderField.Field));
isFirstField = false;
}
query = query.OrderByDescending(x => x.CreatedAt).ThenByDescending(x => x.Id);

// Luôn thêm `ThenByDescending(x => x.Id)` để đảm bảo thứ tự duy nhất
query = ((IOrderedQueryable<TEntity>)query).ThenByDescending(x => x.Id);
}

// Áp dụng điều kiện Cursor
if (!string.IsNullOrEmpty(spec.Cursor))
{
var cursorParts = spec.Cursor.Split('|');
var cursorId = cursorParts.Length == 2 ? cursorParts[1] : null;
if (cursorParts.Length == 2 &&
DateTime.TryParse(cursorParts[0], out var cursorDateTime))
if (cursorParts.Length == 2 && DateTime.TryParse(cursorParts[0], out var cursorDateTime))
{
// Điều kiện Cursor dựa trên hướng sắp xếp
if (spec.OrderFields == null)
{
query = query.Where(x =>
x.CreatedAt < cursorDateTime ||
(x.CreatedAt == cursorDateTime && x.Id.ToString().CompareTo(cursorId) < 0));
}
else
{
query = query.Where(x =>
x.CreatedAt > cursorDateTime ||
(x.CreatedAt == cursorDateTime && x.Id.ToString().CompareTo(cursorId) > 0));
}
var cursorId = cursorParts[1];
query = query.Where(x =>
x.CreatedAt < cursorDateTime ||
(x.CreatedAt == cursorDateTime && x.Id.ToString().CompareTo(cursorId) < 0));
}
}

// Lấy dữ liệu phân trang
var items = await query.Take(spec.Limit + 1).ToListAsync();

// Xác định Cursor tiếp theo (chỉ khi có đủ dữ liệu để phân trang)
string nextCursor = items.Count == spec.Limit + 1
var hasMoreItems = items.Count > spec.Limit;
var nextCursor = hasMoreItems
? $"{items.Last().CreatedAt:O}|{items.Last().Id}"
: null;

// Xác định Cursor trước (chỉ khi có dữ liệu và có cursor đầu vào)
string prevCursor = items.Count > 0 && !string.IsNullOrEmpty(spec.Cursor)
? $"{items.First().CreatedAt:O}|{items.First().Id}"
: null;

// Trả về kết quả phân trang
return new CursorPagedResult<TEntity>
{
Items = items.Take(spec.Limit).ToList(),
NextCursor = nextCursor,
PrevCursor = prevCursor
PrevCursor = !string.IsNullOrEmpty(spec.Cursor)
? $"{items.First().CreatedAt:O}|{items.First().Id}"
: null
};
}


private IQueryable<TEntity> ApplySpecification(ISqlSpecification<TEntity> spec)
{
IQueryable<TEntity> query = DbSet;
Expand Down
21 changes: 14 additions & 7 deletions Profile.Application/Services/UserProfileService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,29 +166,36 @@ 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);
var friendsOfMutualFriends = await relationshipClient.GetFriendsOfMutualFriends(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 mutualFriendIds = friendsOfMutualFriends
//.Select(item => item.ProfileId)
//.ToList();
var suggestionIds = await userProfileRepository.GetTopProfileAsync(50);
var suggestionIdStrings = suggestionIds.Select(id => id.ToString()).ToList();
//var mergedIds = mutualFriendIds
// .Union(suggestionIdStrings)
// .ToList();

var specification = new SpecificationWithCursor<UserProfile>
{
Criteria = userProfile =>
mutualFriendIds.Contains(userProfile.Id.ToString())
& !userProfile.Id.Equals(Guid.Parse(profileId))
suggestionIds.Contains(userProfile.Id)
& !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);
var ok = await userProfileRepository.GetPagedAsync(specification);
return ok;
}

public async Task<CursorPagedResult<UserProfile>> SearchFriend(string keywords, string profileId, string cursor, int limit)
Expand Down
2 changes: 1 addition & 1 deletion Profile.Domain/Repositories/IUserProfileRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public interface IUserProfileRepository : ISqlRepository<UserProfile, Guid>
// tầng BLL(BUS) <==> service
// tầng GUI <==> controller (ở đây là api thay vì view)
Task<UserProfile> GetByAccountIdAsync(Guid accountId);

Task<IList<Guid>> GetTopProfileAsync(int limit);
Task<IList<UserProfile>> GetAllByIdsAsync(IEnumerable<Guid> ids);

}
Expand Down
9 changes: 9 additions & 0 deletions Profile.Infrastructure/Repositories/UserProfileRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,14 @@ public async Task<UserProfile> GetByAccountIdAsync(Guid accountId)

public async Task<IList<UserProfile>> GetAllByIdsAsync(IEnumerable<Guid> ids)
=> await DbSet.Where(profile => ids.Contains(profile.Id)).ToListAsync();

public async Task<IList<Guid>> GetTopProfileAsync(int limit)
{
return await DbSet
.OrderBy(u => u.Id)
.Take(limit)
.Select(u=> u.Id)
.ToListAsync();
}
}
}
35 changes: 17 additions & 18 deletions Profile.Presentation/Controllers/FriendController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,11 @@ public class FriendController(
[ProducesResponseType(typeof(CursorPagedResult<FriendshipResponse>), StatusCodes.Status200OK)]
[Authorize]
[HttpGet("suggestions")]
public async Task<IActionResult> GetFriendSuggestions([FromQuery] string nextCursor, [FromQuery] int limit = 10)
public async Task<IActionResult> GetFriendSuggestions([FromQuery] string cursor, [FromQuery] int limit = 100)
{
string currentProfileId = GetCurrentProfileId != null ? GetCurrentProfileId().ToString()
: throw new BaseException(BaseError.PROFILE_NOT_FOUND, StatusCodes.Status404NotFound);

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

var photoMetadataIds = suggestions.Items
.Where(profile => profile.AvatarId != null)
Expand Down Expand Up @@ -91,18 +90,18 @@ public async Task<IActionResult> GetFriendSuggestions([FromQuery] string nextCur
});
}

[EndpointDescription("Retrieve friend suggestions")]
[EndpointDescription("search friend suggestions")]
[ProducesResponseType(typeof(CursorPagedResult<FriendshipResponse>), StatusCodes.Status200OK)]
[Authorize]
[HttpGet("search")]
public async Task<IActionResult> SearchFriends([FromQuery] string nextCursor, [FromQuery] int limit = 10)
public async Task<IActionResult> SearchFriends([FromQuery] string query, [FromQuery] string cursor, [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 searchResult = await userProfileService.SearchFriend(query, currentProfileId, cursor, limit);

var photoMetadataIds = suggestions.Items
var photoMetadataIds = searchResult.Items
.Where(profile => profile.AvatarId != null)
.Select(profile => profile.AvatarId)
.Distinct();
Expand All @@ -115,12 +114,12 @@ public async Task<IActionResult> SearchFriends([FromQuery] string nextCursor, [F
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());
.CountMutualFriends(currentProfileId, searchResult.Items.Select(f => f.Id.ToString()).ToList());

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

IList<FriendshipResponse> result = [];
foreach (var item in suggestions.Items)
foreach (var item in searchResult.Items)
{
var userProfile = mapper.Map<UserProfileResponse>(item);
if (userProfile.Avatar != null)
Expand All @@ -142,19 +141,19 @@ public async Task<IActionResult> SearchFriends([FromQuery] string nextCursor, [F
return Ok(new CursorPagedResult<FriendshipResponse>()
{
Items = result,
NextCursor = suggestions.NextCursor
NextCursor = searchResult.NextCursor
});
}
//[EndpointDescription("Retrieve requests")]
//[ProducesResponseType(typeof(CursorPagedResult<FriendSuggestionResponse>), StatusCodes.Status200OK)]
//[Authorize]
//[HttpGet("requests")]
//public async Task<IActionResult> GetFriendRequests([FromQuery] string nextCursor, [FromQuery] int limit = 10)
//public async Task<IActionResult> GetFriendRequests([FromQuery] string cursor, [FromQuery] int limit = 10)
//{
// string currentProfileId = GetCurrentProfileId != null ? GetCurrentProfileId().ToString()
// : throw new BaseException(BaseError.PROFILE_NOT_FOUND, StatusCodes.Status404NotFound);

// var friendRequests = await userProfileService.GetFriendRequests(currentProfileId, nextCursor, limit);
// var friendRequests = await userProfileService.GetFriendRequests(currentProfileId, cursor, limit);

// // Tập hợp toàn bộ các ID cần nạp trước
// var profileIds = friendRequests.Items.Select(item => item.Id.ToString()).Distinct();
Expand Down Expand Up @@ -209,12 +208,12 @@ public async Task<IActionResult> SearchFriends([FromQuery] string nextCursor, [F
//[ProducesResponseType(typeof(CursorPagedResult<FriendSuggestionResponse>), StatusCodes.Status200OK)]
//[Authorize]
//[HttpGet("sent-requests")]
//public async Task<IActionResult> GetFriendSentRequests([FromQuery] string nextCursor, [FromQuery] int limit = 10)
//public async Task<IActionResult> GetFriendSentRequests([FromQuery] string cursor, [FromQuery] int limit = 10)
//{
// string currentProfileId = GetCurrentProfileId != null ? GetCurrentProfileId().ToString()
// : throw new BaseException(BaseError.PROFILE_NOT_FOUND, StatusCodes.Status404NotFound);

// var friendSentRequests = await userProfileService.GetFriendSentRequests(currentProfileId, nextCursor, limit);
// var friendSentRequests = await userProfileService.GetFriendSentRequests(currentProfileId, cursor, limit);

// // Tập hợp toàn bộ các ID cần nạp trước
// var profileIds = friendSentRequests.Items.Select(item => item.Id.ToString()).Distinct();
Expand Down Expand Up @@ -269,12 +268,12 @@ public async Task<IActionResult> SearchFriends([FromQuery] string nextCursor, [F
//[ProducesResponseType(typeof(CursorPagedResult<FriendSuggestionResponse>), StatusCodes.Status200OK)]
//[Authorize]
//[HttpGet]
//public async Task<IActionResult> GetFriends([FromQuery] string nextCursor, [FromQuery] int limit = 10)
//public async Task<IActionResult> GetFriends([FromQuery] string cursor, [FromQuery] int limit = 10)
//{
// string currentProfileId = GetCurrentProfileId != null ? GetCurrentProfileId().ToString()
// : throw new BaseException(BaseError.PROFILE_NOT_FOUND, StatusCodes.Status404NotFound);

// var friends = await userProfileService.GetFriends(currentProfileId, nextCursor, limit);
// var friends = await userProfileService.GetFriends(currentProfileId, cursor, limit);

// // Tập hợp toàn bộ các ID cần nạp trước
// var profileIds = friends.Items.Select(item => item.Id.ToString()).Distinct();
Expand Down Expand Up @@ -329,12 +328,12 @@ public async Task<IActionResult> SearchFriends([FromQuery] string nextCursor, [F
[ProducesResponseType(typeof(CursorPagedResult<BlockeeResponse>), StatusCodes.Status200OK)]
[Authorize]
[HttpGet("blocked-list")]
public async Task<IActionResult> GetBlookee([FromQuery] string nextCursor, [FromQuery] int limit = 10)
public async Task<IActionResult> GetBlookee([FromQuery] string cursor, [FromQuery] int limit = 10)
{
string currentProfileId = GetCurrentProfileId != null ? GetCurrentProfileId().ToString()
: throw new BaseException(BaseError.PROFILE_NOT_FOUND, StatusCodes.Status404NotFound);

var blookees = await userProfileService.GetBlockedList(currentProfileId, nextCursor, limit);
var blookees = await userProfileService.GetBlockedList(currentProfileId, cursor, limit);

// Tập hợp toàn bộ các ID cần nạp trước
var profileIds = blookees.Items.Select(item => item.Id.ToString()).Distinct();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,5 @@ public override async Task<MutualFriendCountResponse> countMutualFriends(MutualF
response.ProfileIdsWithMutualCounts.AddRange(source.Select(mapper.Map<ProfileIdWithMutualCount>));
return response;
}

}
}
12 changes: 6 additions & 6 deletions Relationship.Presentation/Controllers/FriendshipController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@ public async Task<IActionResult> GetFriends(string profileId)
[ProducesResponseType(typeof(CursorPagedResult<FriendshipResponse>), StatusCodes.Status200OK)]
[Authorize]
[HttpGet("requests")]
public async Task<IActionResult> GetFriendRequests([FromQuery] string nextCursor, [FromQuery] int limit = 10)
public async Task<IActionResult> GetFriendRequests([FromQuery] string cursor, [FromQuery] int limit = 10)
{
string currentProfileId = GetCurrentProfileId != null ? GetCurrentProfileId().ToString()
: throw new BaseException(BaseError.PROFILE_NOT_FOUND, StatusCodes.Status404NotFound);

var friendRequests = await friendshipService.GetFriendRequests(currentProfileId, nextCursor, limit);
var friendRequests = await friendshipService.GetFriendRequests(currentProfileId, cursor, limit);

// Tập hợp toàn bộ các ID cần nạp trước
var profileIds = friendRequests.Items.Select(item => item.SenderId.ToString()).Distinct();
Expand Down Expand Up @@ -133,12 +133,12 @@ public async Task<IActionResult> GetFriendRequests([FromQuery] string nextCursor
[ProducesResponseType(typeof(CursorPagedResult<FriendshipResponse>), StatusCodes.Status200OK)]
[Authorize]
[HttpGet("sent-requests")]
public async Task<IActionResult> GetFriendSentRequests([FromQuery] string nextCursor, [FromQuery] int limit = 10)
public async Task<IActionResult> GetFriendSentRequests([FromQuery] string cursor, [FromQuery] int limit = 10)
{
string currentProfileId = GetCurrentProfileId != null ? GetCurrentProfileId().ToString()
: throw new BaseException(BaseError.PROFILE_NOT_FOUND, StatusCodes.Status404NotFound);

var friendSentRequests = await friendshipService.GetFriendSentRequests(currentProfileId, nextCursor, limit);
var friendSentRequests = await friendshipService.GetFriendSentRequests(currentProfileId, cursor, limit);

// Tập hợp toàn bộ các ID cần nạp trước
var profileIds = friendSentRequests.Items.Select(item => item.ReceiverId.ToString()).Distinct();
Expand Down Expand Up @@ -195,12 +195,12 @@ public async Task<IActionResult> GetFriendSentRequests([FromQuery] string nextCu
[ProducesResponseType(typeof(CursorPagedResult<FriendshipResponse>), StatusCodes.Status200OK)]
[Authorize]
[HttpGet]
public async Task<IActionResult> GetFriends([FromQuery] string nextCursor, [FromQuery] int limit = 10)
public async Task<IActionResult> GetFriends([FromQuery] string cursor, [FromQuery] int limit = 10)
{
string currentProfileId = GetCurrentProfileId != null ? GetCurrentProfileId().ToString()
: throw new BaseException(BaseError.PROFILE_NOT_FOUND, StatusCodes.Status404NotFound);

var friends = await friendshipService.GetFriends(currentProfileId, nextCursor, limit);
var friends = await friendshipService.GetFriends(currentProfileId, cursor, limit);

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