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
29 changes: 28 additions & 1 deletion src/pythonxbox/api/provider/people/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
People - Access friendlist from own profiles and others
People - Access friendlist and profile info from own profile and others
"""

from typing import TYPE_CHECKING, ClassVar
Expand Down Expand Up @@ -93,6 +93,33 @@ async def get_friends_by_xuid(
resp.raise_for_status()
return PeopleResponse.model_validate_json(resp.text)

async def get_friend_by_xuid(self, xuid: str, decoration_fields: list[PeopleDecoration] | None = None, **kwargs) -> PeopleResponse:
"""
Get a single friend's profile from the authenticated user's perspective

This returns relationship metadata (isFriend, canBeFriended, etc.) as seen
by the caller, making it useful for profile lookups and relationship checks.

Args:
xuid: XUID of the user to retrieve profile for

Returns:
:class:`PeopleResponse`: People Response with a single person entry
"""
if not decoration_fields:
decoration_fields = [
PeopleDecoration.PREFERRED_COLOR,
PeopleDecoration.DETAIL,
PeopleDecoration.MULTIPLAYER_SUMMARY,
PeopleDecoration.PRESENCE_DETAIL,
]
decoration = self.SEPERATOR.join(decoration_fields)

url = f"{self.PEOPLE_URL}/users/me/people/xuids({xuid})/decoration/{decoration}"
resp = await self.client.session.get(url, headers=self._headers, **kwargs)
resp.raise_for_status()
return PeopleResponse.model_validate_json(resp.text)

async def get_friends_own_batch(
self,
xuids: list[str],
Expand Down
87 changes: 87 additions & 0 deletions tests/data/responses/people_profile_by_xuid.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{
"people": [
{
"xuid": "2533274812261808",
"isFavorite": false,
"isFollowingCaller": false,
"isFollowedByCaller": true,
"isIdentityShared": false,
"addedDateTimeUtc": null,
"displayName": "VolekTheFNDwarf",
"realName": "",
"displayPicRaw": "https://images-eds-ssl.xboxlive.com/image?url=wHwbXKif8cus8csoZ03RW3apWESZjav65Yncai8aRmVbSlZ3zqRpg1sdxEje_JmFTQaIPE",
"showUserAsAvatar": "1",
"gamertag": "VolekTheFNDwarf",
"gamerScore": "70700",
"modernGamertag": "VolekTheFNDwarf",
"modernGamertagSuffix": "",
"uniqueModernGamertag": "VolekTheFNDwarf",
"xboxOneRep": "GoodPlayer",
"presenceState": "Offline",
"presenceText": "Offline",
"presenceDevices": null,
"isFriend": true,
"isFriendRequestReceived": false,
"isFriendRequestSent": false,
"isBroadcasting": false,
"isCloaked": null,
"isQuarantined": false,
"isXbox360Gamerpic": false,
"lastSeenDateTimeUtc": null,
"suggestion": null,
"recommendation": null,
"search": null,
"titleHistory": null,
"multiplayerSummary": {
"inMultiplayerSession": 0,
"inParty": 0
},
"recentPlayer": null,
"follower": null,
"preferredColor": {
"primaryColor": "1081ca",
"secondaryColor": "10314f",
"tertiaryColor": "105080"
},
"presenceDetails": [],
"titlePresence": null,
"titleSummaries": null,
"presenceTitleIds": null,
"detail": {
"accountTier": "Gold",
"bio": "Lover of nerd culture & those who embrace it.",
"isVerified": false,
"location": "Charlotte",
"tenure": "12",
"watermarks": [],
"blocked": false,
"mute": false,
"followerCount": 50,
"followingCount": 34,
"hasGamePass": false,
"isFriend": true,
"canBeFriended": true,
"canBeFollowed": true,
"friendCount": 150,
"isFriendRequestReceived": false,
"isFriendRequestSent": false,
"isFriendListShared": true,
"isFollowingCaller": false,
"isFollowedByCaller": false,
"isFavorite": false
},
"communityManagerTitles": null,
"socialManager": null,
"broadcast": null,
"tournamentSummary": null,
"avatar": null,
"linkedAccounts": [],
"colorTheme": "gamerpicblur",
"preferredFlag": "",
"preferredPlatforms": []
}
],
"recommendationSummary": null,
"friendFinderState": null,
"accountLinkDetails": null
}
15 changes: 15 additions & 0 deletions tests/test_people.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,21 @@ async def test_people_friends_by_xuid(
assert route.called


@pytest.mark.asyncio
async def test_people_friend_by_xuid(
respx_mock: MockRouter, xbl_client: XboxLiveClient
) -> None:
route = respx_mock.get("https://peoplehub.xboxlive.com").mock(
return_value=Response(200, json=get_response_json("people_profile_by_xuid"))
)
ret = await xbl_client.people.get_friend_by_xuid("2533274812261808")

assert len(ret.people) == 1
assert ret.people[0].gamertag == "VolekTheFNDwarf"
assert ret.people[0].is_friend is True
assert route.called


@pytest.mark.asyncio
async def test_profiles_batch(
respx_mock: MockRouter, xbl_client: XboxLiveClient
Expand Down
Loading