Add account family + storage services (#250)
This commit is contained in:
parent
91ac1d956e
commit
e3bdcea15a
9 changed files with 523 additions and 45 deletions
|
@ -13,34 +13,68 @@ class AccountService(object):
|
||||||
self.session = session
|
self.session = session
|
||||||
self.params = params
|
self.params = params
|
||||||
self._service_root = service_root
|
self._service_root = service_root
|
||||||
|
|
||||||
self._devices = []
|
self._devices = []
|
||||||
|
self._family = []
|
||||||
|
self._storage = None
|
||||||
|
|
||||||
self._acc_endpoint = "%s/setup/web/device" % self._service_root
|
self._acc_endpoint = "%s/setup/web" % self._service_root
|
||||||
self._account_devices_url = "%s/getDevices" % self._acc_endpoint
|
self._acc_devices_url = "%s/device/getDevices" % self._acc_endpoint
|
||||||
|
self._acc_family_details_url = "%s/family/getFamilyDetails" % self._acc_endpoint
|
||||||
req = self.session.get(self._account_devices_url, params=self.params)
|
self._acc_family_member_photo_url = (
|
||||||
self.response = req.json()
|
"%s/family/getMemberPhoto" % self._acc_endpoint
|
||||||
|
)
|
||||||
for device_info in self.response["devices"]:
|
self._acc_storage_url = "https://setup.icloud.com/setup/ws/1/storageUsageInfo"
|
||||||
# device_id = device_info['udid']
|
|
||||||
# self._devices[device_id] = AccountDevice(device_info)
|
|
||||||
self._devices.append(AccountDevice(device_info))
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def devices(self):
|
def devices(self):
|
||||||
"""Gets the account devices."""
|
"""Returns current paired devices."""
|
||||||
|
if not self._devices:
|
||||||
|
req = self.session.get(self._acc_devices_url, params=self.params)
|
||||||
|
response = req.json()
|
||||||
|
|
||||||
|
for device_info in response["devices"]:
|
||||||
|
self._devices.append(AccountDevice(device_info))
|
||||||
|
|
||||||
return self._devices
|
return self._devices
|
||||||
|
|
||||||
|
@property
|
||||||
|
def family(self):
|
||||||
|
"""Returns family members."""
|
||||||
|
if not self._family:
|
||||||
|
req = self.session.get(self._acc_family_details_url, params=self.params)
|
||||||
|
response = req.json()
|
||||||
|
|
||||||
|
for member_info in response["familyMembers"]:
|
||||||
|
self._family.append(
|
||||||
|
FamilyMember(
|
||||||
|
member_info,
|
||||||
|
self.session,
|
||||||
|
self.params,
|
||||||
|
self._acc_family_member_photo_url,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return self._family
|
||||||
|
|
||||||
|
@property
|
||||||
|
def storage(self):
|
||||||
|
"""Returns storage infos."""
|
||||||
|
if not self._storage:
|
||||||
|
req = self.session.get(self._acc_storage_url, params=self.params)
|
||||||
|
response = req.json()
|
||||||
|
|
||||||
|
self._storage = AccountStorage(response)
|
||||||
|
|
||||||
|
return self._storage
|
||||||
|
|
||||||
|
|
||||||
@six.python_2_unicode_compatible
|
@six.python_2_unicode_compatible
|
||||||
class AccountDevice(dict):
|
class AccountDevice(dict):
|
||||||
"""Account device."""
|
"""Account device."""
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, key):
|
||||||
try:
|
return self[underscore_to_camelcase(key)]
|
||||||
return self[underscore_to_camelcase(name)]
|
|
||||||
except KeyError:
|
|
||||||
raise AttributeError(name)
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return u"{display_name}: {name}".format(
|
return u"{display_name}: {name}".format(
|
||||||
|
@ -55,3 +89,251 @@ class AccountDevice(dict):
|
||||||
else six.text_type(self).encode("utf8", "replace")
|
else six.text_type(self).encode("utf8", "replace")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class FamilyMember(object):
|
||||||
|
"""A family member."""
|
||||||
|
|
||||||
|
def __init__(self, member_info, session, params, acc_family_member_photo_url):
|
||||||
|
self._attrs = member_info
|
||||||
|
self._session = session
|
||||||
|
self._params = params
|
||||||
|
self._acc_family_member_photo_url = acc_family_member_photo_url
|
||||||
|
|
||||||
|
@property
|
||||||
|
def last_name(self):
|
||||||
|
"""Gets the last name."""
|
||||||
|
return self._attrs.get("lastName")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dsid(self):
|
||||||
|
"""Gets the dsid."""
|
||||||
|
return self._attrs.get("dsid")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def original_invitation_email(self):
|
||||||
|
"""Gets the original invitation."""
|
||||||
|
return self._attrs.get("originalInvitationEmail")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def full_name(self):
|
||||||
|
"""Gets the full name."""
|
||||||
|
return self._attrs.get("fullName")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def age_classification(self):
|
||||||
|
"""Gets the age classification."""
|
||||||
|
return self._attrs.get("ageClassification")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def apple_id_for_purchases(self):
|
||||||
|
"""Gets the apple id for purchases."""
|
||||||
|
return self._attrs.get("appleIdForPurchases")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def apple_id(self):
|
||||||
|
"""Gets the apple id."""
|
||||||
|
return self._attrs.get("appleId")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def family_id(self):
|
||||||
|
"""Gets the family id."""
|
||||||
|
return self._attrs.get("familyId")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def first_name(self):
|
||||||
|
"""Gets the first name."""
|
||||||
|
return self._attrs.get("firstName")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_parental_privileges(self):
|
||||||
|
"""Has parental privileges."""
|
||||||
|
return self._attrs.get("hasParentalPrivileges")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_screen_time_enabled(self):
|
||||||
|
"""Has screen time enabled."""
|
||||||
|
return self._attrs.get("hasScreenTimeEnabled")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_ask_to_buy_enabled(self):
|
||||||
|
"""Has to ask for buying."""
|
||||||
|
return self._attrs.get("hasAskToBuyEnabled")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_share_purchases_enabled(self):
|
||||||
|
"""Has share purshases."""
|
||||||
|
return self._attrs.get("hasSharePurchasesEnabled")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def share_my_location_enabled_family_members(self):
|
||||||
|
"""Has share my location with family."""
|
||||||
|
return self._attrs.get("shareMyLocationEnabledFamilyMembers")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_share_my_location_enabled(self):
|
||||||
|
"""Has share my location."""
|
||||||
|
return self._attrs.get("hasShareMyLocationEnabled")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dsid_for_purchases(self):
|
||||||
|
"""Gets the dsid for purchases."""
|
||||||
|
return self._attrs.get("dsidForPurchases")
|
||||||
|
|
||||||
|
def get_photo(self):
|
||||||
|
"""Returns the photo."""
|
||||||
|
params_photo = dict(self._params)
|
||||||
|
params_photo.update({"memberId": self.dsid})
|
||||||
|
return self._session.get(
|
||||||
|
self._acc_family_member_photo_url, params=params_photo, stream=True
|
||||||
|
)
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
if self._attrs.get(key):
|
||||||
|
return self._attrs[key]
|
||||||
|
return getattr(self, key)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return u"{full_name}: {age_classification}".format(
|
||||||
|
full_name=self.full_name, age_classification=self.age_classification,
|
||||||
|
)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<{display}>".format(
|
||||||
|
display=(
|
||||||
|
six.text_type(self)
|
||||||
|
if sys.version_info[0] >= 3
|
||||||
|
else six.text_type(self).encode("utf8", "replace")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AccountStorageUsageForMedia(object):
|
||||||
|
"""Storage used for a specific media type into the account."""
|
||||||
|
|
||||||
|
def __init__(self, usage_data):
|
||||||
|
self.usage_data = usage_data
|
||||||
|
|
||||||
|
@property
|
||||||
|
def key(self):
|
||||||
|
"""Gets the key."""
|
||||||
|
return self.usage_data["mediaKey"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def label(self):
|
||||||
|
"""Gets the label."""
|
||||||
|
return self.usage_data["displayLabel"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def color(self):
|
||||||
|
"""Gets the HEX color."""
|
||||||
|
return self.usage_data["displayColor"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def usage_in_bytes(self):
|
||||||
|
"""Gets the usage in bytes."""
|
||||||
|
return self.usage_data["usageInBytes"]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return u"{key}: {usage}".format(key=self.key, usage=self.usage_in_bytes)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<{display}>".format(
|
||||||
|
display=(
|
||||||
|
six.text_type(self)
|
||||||
|
if sys.version_info[0] >= 3
|
||||||
|
else six.text_type(self).encode("utf8", "replace")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AccountStorageUsage(object):
|
||||||
|
"""Storage used for a specific media type into the account."""
|
||||||
|
|
||||||
|
def __init__(self, usage_data, quota_data):
|
||||||
|
self.usage_data = usage_data
|
||||||
|
self.quota_data = quota_data
|
||||||
|
|
||||||
|
@property
|
||||||
|
def comp_storage_in_bytes(self):
|
||||||
|
"""Gets the comp storage in bytes."""
|
||||||
|
return self.usage_data["compStorageInBytes"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def used_storage_in_bytes(self):
|
||||||
|
"""Gets the used storage in bytes."""
|
||||||
|
return self.usage_data["usedStorageInBytes"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def used_storage_in_percent(self):
|
||||||
|
"""Gets the used storage in percent."""
|
||||||
|
return self.used_storage_in_bytes * 100 / self.total_storage_in_bytes
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available_storage_in_bytes(self):
|
||||||
|
"""Gets the available storage in bytes."""
|
||||||
|
return self.total_storage_in_bytes - self.used_storage_in_bytes
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available_storage_in_percent(self):
|
||||||
|
"""Gets the available storage in percent."""
|
||||||
|
return self.available_storage_in_bytes * 100 / self.total_storage_in_bytes
|
||||||
|
|
||||||
|
@property
|
||||||
|
def total_storage_in_bytes(self):
|
||||||
|
"""Gets the total storage in bytes."""
|
||||||
|
return self.usage_data["totalStorageInBytes"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def commerce_storage_in_bytes(self):
|
||||||
|
"""Gets the commerce storage in bytes."""
|
||||||
|
return self.usage_data["commerceStorageInBytes"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def quota_over(self):
|
||||||
|
"""Gets the over quota."""
|
||||||
|
return self.quota_data["overQuota"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def quota_tier_max(self):
|
||||||
|
"""Gets the max tier quota."""
|
||||||
|
return self.quota_data["haveMaxQuotaTier"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def quota_almost_full(self):
|
||||||
|
"""Gets the almost full quota."""
|
||||||
|
return self.quota_data["almost-full"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def quota_paid(self):
|
||||||
|
"""Gets the paid quota."""
|
||||||
|
return self.quota_data["paidQuota"]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return u"{used_percent}%% used of {total} bytes".format(
|
||||||
|
used_percent=self.used_storage_in_percent, total=self.total_storage_in_bytes
|
||||||
|
)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<{display}>".format(
|
||||||
|
display=(
|
||||||
|
six.text_type(self)
|
||||||
|
if sys.version_info[0] >= 3
|
||||||
|
else six.text_type(self).encode("utf8", "replace")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AccountStorage(object):
|
||||||
|
"""Storage of the account."""
|
||||||
|
|
||||||
|
def __init__(self, storage_data):
|
||||||
|
self.usage = AccountStorageUsage(
|
||||||
|
storage_data.get("storageUsageInfo"), storage_data.get("quotaStatus")
|
||||||
|
)
|
||||||
|
self.usages_by_media = {}
|
||||||
|
|
||||||
|
for usage_media in storage_data.get("storageUsageByMedia"):
|
||||||
|
self.usages_by_media[usage_media["mediaKey"]] = AccountStorageUsageForMedia(
|
||||||
|
usage_media
|
||||||
|
)
|
||||||
|
|
|
@ -20,8 +20,9 @@ from .const_login import (
|
||||||
VERIFICATION_CODE_OK,
|
VERIFICATION_CODE_OK,
|
||||||
VERIFICATION_CODE_KO,
|
VERIFICATION_CODE_KO,
|
||||||
)
|
)
|
||||||
from .const_account import ACCOUNT_DEVICES_WORKING
|
from .const_account import ACCOUNT_DEVICES_WORKING, ACCOUNT_STORAGE_WORKING
|
||||||
from .const_findmyiphone import FMI_FMLY_WORKING
|
from .const_account_family import ACCOUNT_FAMILY_WORKING
|
||||||
|
from .const_findmyiphone import FMI_FAMILY_WORKING
|
||||||
|
|
||||||
|
|
||||||
class ResponseMock(Response):
|
class ResponseMock(Response):
|
||||||
|
@ -76,10 +77,14 @@ class PyiCloudSessionMock(base.PyiCloudSession):
|
||||||
# Account
|
# Account
|
||||||
if "device/getDevices" in url and method == "GET":
|
if "device/getDevices" in url and method == "GET":
|
||||||
return ResponseMock(ACCOUNT_DEVICES_WORKING)
|
return ResponseMock(ACCOUNT_DEVICES_WORKING)
|
||||||
|
if "family/getFamilyDetails" in url and method == "GET":
|
||||||
|
return ResponseMock(ACCOUNT_FAMILY_WORKING)
|
||||||
|
if "setup/ws/1/storageUsageInfo" in url and method == "GET":
|
||||||
|
return ResponseMock(ACCOUNT_STORAGE_WORKING)
|
||||||
|
|
||||||
# Find My iPhone
|
# Find My iPhone
|
||||||
if "fmi" in url and method == "POST":
|
if "fmi" in url and method == "POST":
|
||||||
return ResponseMock(FMI_FMLY_WORKING)
|
return ResponseMock(FMI_FAMILY_WORKING)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
"""Test constants."""
|
"""Test constants."""
|
||||||
from .const_login import PRIMARY_EMAIL, APPLE_ID_EMAIL, ICLOUD_ID_EMAIL
|
from .const_account_family import PRIMARY_EMAIL, APPLE_ID_EMAIL, ICLOUD_ID_EMAIL
|
||||||
|
|
||||||
# Base
|
# Base
|
||||||
AUTHENTICATED_USER = PRIMARY_EMAIL
|
AUTHENTICATED_USER = PRIMARY_EMAIL
|
||||||
|
|
|
@ -75,3 +75,45 @@ ACCOUNT_DEVICES_WORKING = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ACCOUNT_STORAGE_WORKING = {
|
||||||
|
"storageUsageByMedia": [
|
||||||
|
{
|
||||||
|
"mediaKey": "photos",
|
||||||
|
"displayLabel": "Photos et vidéos",
|
||||||
|
"displayColor": "ffcc00",
|
||||||
|
"usageInBytes": 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mediaKey": "backup",
|
||||||
|
"displayLabel": "Sauvegarde",
|
||||||
|
"displayColor": "5856d6",
|
||||||
|
"usageInBytes": 799008186,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mediaKey": "docs",
|
||||||
|
"displayLabel": "Documents",
|
||||||
|
"displayColor": "ff9500",
|
||||||
|
"usageInBytes": 449092146,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mediaKey": "mail",
|
||||||
|
"displayLabel": "Mail",
|
||||||
|
"displayColor": "007aff",
|
||||||
|
"usageInBytes": 1101522944,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"storageUsageInfo": {
|
||||||
|
"compStorageInBytes": 0,
|
||||||
|
"usedStorageInBytes": 2348632876,
|
||||||
|
"totalStorageInBytes": 5368709120,
|
||||||
|
"commerceStorageInBytes": 0,
|
||||||
|
},
|
||||||
|
"quotaStatus": {
|
||||||
|
"overQuota": False,
|
||||||
|
"haveMaxQuotaTier": False,
|
||||||
|
"almost-full": False,
|
||||||
|
"paidQuota": False,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
97
tests/const_account_family.py
Normal file
97
tests/const_account_family.py
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
"""Account family test constants."""
|
||||||
|
|
||||||
|
# Fakers
|
||||||
|
FIRST_NAME = "Quentin"
|
||||||
|
LAST_NAME = "TARANTINO"
|
||||||
|
FULL_NAME = FIRST_NAME + " " + LAST_NAME
|
||||||
|
PERSON_ID = (FIRST_NAME + LAST_NAME).lower()
|
||||||
|
PRIMARY_EMAIL = PERSON_ID + "@hotmail.fr"
|
||||||
|
APPLE_ID_EMAIL = PERSON_ID + "@me.com"
|
||||||
|
ICLOUD_ID_EMAIL = PERSON_ID + "@icloud.com"
|
||||||
|
|
||||||
|
MEMBER_1_FIRST_NAME = "John"
|
||||||
|
MEMBER_1_LAST_NAME = "TRAVOLTA"
|
||||||
|
MEMBER_1_FULL_NAME = MEMBER_1_FIRST_NAME + " " + MEMBER_1_LAST_NAME
|
||||||
|
MEMBER_1_PERSON_ID = (MEMBER_1_FIRST_NAME + MEMBER_1_LAST_NAME).lower()
|
||||||
|
MEMBER_1_APPLE_ID = MEMBER_1_PERSON_ID + "@icloud.com"
|
||||||
|
|
||||||
|
MEMBER_2_FIRST_NAME = "Uma"
|
||||||
|
MEMBER_2_LAST_NAME = "THURMAN"
|
||||||
|
MEMBER_2_FULL_NAME = MEMBER_2_FIRST_NAME + " " + MEMBER_2_LAST_NAME
|
||||||
|
MEMBER_2_PERSON_ID = (MEMBER_2_FIRST_NAME + MEMBER_2_LAST_NAME).lower()
|
||||||
|
MEMBER_2_APPLE_ID = MEMBER_2_PERSON_ID + "@outlook.fr"
|
||||||
|
|
||||||
|
FAMILY_ID = "family_" + PERSON_ID
|
||||||
|
|
||||||
|
# Data
|
||||||
|
ACCOUNT_FAMILY_WORKING = {
|
||||||
|
"status-message": "Member of a family.",
|
||||||
|
"familyInvitations": [],
|
||||||
|
"outgoingTransferRequests": [],
|
||||||
|
"isMemberOfFamily": True,
|
||||||
|
"family": {
|
||||||
|
"familyId": FAMILY_ID,
|
||||||
|
"transferRequests": [],
|
||||||
|
"invitations": [],
|
||||||
|
"organizer": PERSON_ID,
|
||||||
|
"members": [PERSON_ID, MEMBER_2_PERSON_ID, MEMBER_1_PERSON_ID],
|
||||||
|
"outgoingTransferRequests": [],
|
||||||
|
"etag": "12",
|
||||||
|
},
|
||||||
|
"familyMembers": [
|
||||||
|
{
|
||||||
|
"lastName": LAST_NAME,
|
||||||
|
"dsid": PERSON_ID,
|
||||||
|
"originalInvitationEmail": PRIMARY_EMAIL,
|
||||||
|
"fullName": FULL_NAME,
|
||||||
|
"ageClassification": "ADULT",
|
||||||
|
"appleIdForPurchases": PRIMARY_EMAIL,
|
||||||
|
"appleId": PRIMARY_EMAIL,
|
||||||
|
"familyId": FAMILY_ID,
|
||||||
|
"firstName": FIRST_NAME,
|
||||||
|
"hasParentalPrivileges": True,
|
||||||
|
"hasScreenTimeEnabled": False,
|
||||||
|
"hasAskToBuyEnabled": False,
|
||||||
|
"hasSharePurchasesEnabled": True,
|
||||||
|
"shareMyLocationEnabledFamilyMembers": [],
|
||||||
|
"hasShareMyLocationEnabled": True,
|
||||||
|
"dsidForPurchases": PERSON_ID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lastName": MEMBER_2_LAST_NAME,
|
||||||
|
"dsid": MEMBER_2_PERSON_ID,
|
||||||
|
"originalInvitationEmail": MEMBER_2_APPLE_ID,
|
||||||
|
"fullName": MEMBER_2_FULL_NAME,
|
||||||
|
"ageClassification": "ADULT",
|
||||||
|
"appleIdForPurchases": MEMBER_2_APPLE_ID,
|
||||||
|
"appleId": MEMBER_2_APPLE_ID,
|
||||||
|
"familyId": FAMILY_ID,
|
||||||
|
"firstName": MEMBER_2_FIRST_NAME,
|
||||||
|
"hasParentalPrivileges": False,
|
||||||
|
"hasScreenTimeEnabled": False,
|
||||||
|
"hasAskToBuyEnabled": False,
|
||||||
|
"hasSharePurchasesEnabled": False,
|
||||||
|
"hasShareMyLocationEnabled": False,
|
||||||
|
"dsidForPurchases": MEMBER_2_PERSON_ID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lastName": MEMBER_1_LAST_NAME,
|
||||||
|
"dsid": MEMBER_1_PERSON_ID,
|
||||||
|
"originalInvitationEmail": MEMBER_1_APPLE_ID,
|
||||||
|
"fullName": MEMBER_1_FULL_NAME,
|
||||||
|
"ageClassification": "ADULT",
|
||||||
|
"appleIdForPurchases": MEMBER_1_APPLE_ID,
|
||||||
|
"appleId": MEMBER_1_APPLE_ID,
|
||||||
|
"familyId": FAMILY_ID,
|
||||||
|
"firstName": MEMBER_1_FIRST_NAME,
|
||||||
|
"hasParentalPrivileges": False,
|
||||||
|
"hasScreenTimeEnabled": False,
|
||||||
|
"hasAskToBuyEnabled": False,
|
||||||
|
"hasSharePurchasesEnabled": True,
|
||||||
|
"hasShareMyLocationEnabled": True,
|
||||||
|
"dsidForPurchases": MEMBER_1_PERSON_ID,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"status": 0,
|
||||||
|
"showAddMemberButton": True,
|
||||||
|
}
|
|
@ -1,17 +1,19 @@
|
||||||
"""Find my iPhone test constants."""
|
"""Find my iPhone test constants."""
|
||||||
from .const import CLIENT_ID
|
from .const import CLIENT_ID
|
||||||
from .const_login import FIRST_NAME, LAST_NAME, PERSON_ID, FULL_NAME
|
from .const_account_family import (
|
||||||
|
FIRST_NAME,
|
||||||
# Base
|
LAST_NAME,
|
||||||
MEMBER_1_FIRST_NAME = "John"
|
PERSON_ID,
|
||||||
MEMBER_1_LAST_NAME = "TRAVOLTA"
|
FULL_NAME,
|
||||||
MEMBER_1_PERSON_ID = (MEMBER_1_FIRST_NAME + MEMBER_1_LAST_NAME).lower()
|
MEMBER_1_FIRST_NAME,
|
||||||
MEMBER_1_APPLE_ID = MEMBER_1_PERSON_ID + "@icloud.com"
|
MEMBER_1_APPLE_ID,
|
||||||
|
MEMBER_1_LAST_NAME,
|
||||||
MEMBER_2_FIRST_NAME = "Uma"
|
MEMBER_1_PERSON_ID,
|
||||||
MEMBER_2_LAST_NAME = "THURMAN"
|
MEMBER_2_APPLE_ID,
|
||||||
MEMBER_2_PERSON_ID = (MEMBER_2_FIRST_NAME + MEMBER_2_LAST_NAME).lower()
|
MEMBER_2_FIRST_NAME,
|
||||||
MEMBER_2_APPLE_ID = MEMBER_2_PERSON_ID + "@outlook.fr"
|
MEMBER_2_LAST_NAME,
|
||||||
|
MEMBER_2_PERSON_ID,
|
||||||
|
)
|
||||||
|
|
||||||
# Fakers
|
# Fakers
|
||||||
UUID = "ABCDEFGH-1234-5678-1234-ABCDEFGHIJKL"
|
UUID = "ABCDEFGH-1234-5678-1234-ABCDEFGHIJKL"
|
||||||
|
@ -23,7 +25,7 @@ LOCATION_LONGITUDE = 6.1234567890123456
|
||||||
# id = rawDeviceModel + prsId (if not None)
|
# id = rawDeviceModel + prsId (if not None)
|
||||||
# baUUID = UUID + id
|
# baUUID = UUID + id
|
||||||
# So they can still be faked and unique
|
# So they can still be faked and unique
|
||||||
FMI_FMLY_WORKING = {
|
FMI_FAMILY_WORKING = {
|
||||||
"userInfo": {
|
"userInfo": {
|
||||||
"accountFormatter": 0,
|
"accountFormatter": 0,
|
||||||
"firstName": FIRST_NAME,
|
"firstName": FIRST_NAME,
|
||||||
|
|
|
@ -1,20 +1,19 @@
|
||||||
"""Login test constants."""
|
"""Login test constants."""
|
||||||
|
from .const_account_family import (
|
||||||
# Base
|
FIRST_NAME,
|
||||||
FIRST_NAME = "Quentin"
|
LAST_NAME,
|
||||||
LAST_NAME = "TARANTINO"
|
PERSON_ID,
|
||||||
FULL_NAME = FIRST_NAME + " " + LAST_NAME
|
FULL_NAME,
|
||||||
|
PRIMARY_EMAIL,
|
||||||
|
APPLE_ID_EMAIL,
|
||||||
|
ICLOUD_ID_EMAIL,
|
||||||
|
)
|
||||||
|
|
||||||
PERSON_ID = (FIRST_NAME + LAST_NAME).lower()
|
PERSON_ID = (FIRST_NAME + LAST_NAME).lower()
|
||||||
NOTIFICATION_ID = "12345678-1234-1234-1234-123456789012" + PERSON_ID
|
NOTIFICATION_ID = "12345678-1234-1234-1234-123456789012" + PERSON_ID
|
||||||
A_DS_ID = "123456-12-12345678-1234-1234-1234-123456789012" + PERSON_ID
|
A_DS_ID = "123456-12-12345678-1234-1234-1234-123456789012" + PERSON_ID
|
||||||
WIDGET_KEY = "widget_key" + PERSON_ID
|
WIDGET_KEY = "widget_key" + PERSON_ID
|
||||||
|
|
||||||
PRIMARY_EMAIL = PERSON_ID + "@hotmail.fr"
|
|
||||||
APPLE_ID_EMAIL = PERSON_ID + "@me.com"
|
|
||||||
ICLOUD_ID_EMAIL = PERSON_ID + "@icloud.com"
|
|
||||||
|
|
||||||
|
|
||||||
# Data
|
# Data
|
||||||
LOGIN_WORKING = {
|
LOGIN_WORKING = {
|
||||||
"dsInfo": {
|
"dsInfo": {
|
||||||
|
|
|
@ -14,6 +14,7 @@ class AccountServiceTest(TestCase):
|
||||||
|
|
||||||
def test_devices(self):
|
def test_devices(self):
|
||||||
"""Tests devices."""
|
"""Tests devices."""
|
||||||
|
assert self.service.devices
|
||||||
assert len(self.service.devices) == 2
|
assert len(self.service.devices) == 2
|
||||||
|
|
||||||
for device in self.service.devices:
|
for device in self.service.devices:
|
||||||
|
@ -31,3 +32,53 @@ class AccountServiceTest(TestCase):
|
||||||
assert device["modelSmallPhotoURL2x"]
|
assert device["modelSmallPhotoURL2x"]
|
||||||
assert device["modelSmallPhotoURL1x"]
|
assert device["modelSmallPhotoURL1x"]
|
||||||
assert device["modelDisplayName"]
|
assert device["modelDisplayName"]
|
||||||
|
|
||||||
|
def test_family(self):
|
||||||
|
"""Tests family members."""
|
||||||
|
assert self.service.family
|
||||||
|
assert len(self.service.family) == 3
|
||||||
|
|
||||||
|
for member in self.service.family:
|
||||||
|
assert member.last_name
|
||||||
|
assert member.dsid
|
||||||
|
assert member.original_invitation_email
|
||||||
|
assert member.full_name
|
||||||
|
assert member.age_classification
|
||||||
|
assert member.apple_id_for_purchases
|
||||||
|
assert member.apple_id
|
||||||
|
assert member.first_name
|
||||||
|
assert not member.has_screen_time_enabled
|
||||||
|
assert not member.has_ask_to_buy_enabled
|
||||||
|
assert not member.share_my_location_enabled_family_members
|
||||||
|
assert member.dsid_for_purchases
|
||||||
|
|
||||||
|
def test_storage(self):
|
||||||
|
"""Tests storage."""
|
||||||
|
assert self.service.storage
|
||||||
|
|
||||||
|
assert self.service.storage.usage
|
||||||
|
assert (
|
||||||
|
self.service.storage.usage.comp_storage_in_bytes
|
||||||
|
or self.service.storage.usage.comp_storage_in_bytes == 0
|
||||||
|
)
|
||||||
|
assert self.service.storage.usage.used_storage_in_bytes
|
||||||
|
assert self.service.storage.usage.used_storage_in_percent
|
||||||
|
assert self.service.storage.usage.available_storage_in_bytes
|
||||||
|
assert self.service.storage.usage.available_storage_in_percent
|
||||||
|
assert self.service.storage.usage.total_storage_in_bytes
|
||||||
|
assert (
|
||||||
|
self.service.storage.usage.commerce_storage_in_bytes
|
||||||
|
or self.service.storage.usage.commerce_storage_in_bytes == 0
|
||||||
|
)
|
||||||
|
assert not self.service.storage.usage.quota_over
|
||||||
|
assert not self.service.storage.usage.quota_tier_max
|
||||||
|
assert not self.service.storage.usage.quota_almost_full
|
||||||
|
assert not self.service.storage.usage.quota_paid
|
||||||
|
|
||||||
|
assert self.service.storage.usages_by_media
|
||||||
|
|
||||||
|
for usage_media in self.service.storage.usages_by_media.values():
|
||||||
|
assert usage_media.key
|
||||||
|
assert usage_media.label
|
||||||
|
assert usage_media.color
|
||||||
|
assert usage_media.usage_in_bytes or usage_media.usage_in_bytes == 0
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
from pyicloud import cmdline
|
from pyicloud import cmdline
|
||||||
from . import PyiCloudServiceMock
|
from . import PyiCloudServiceMock
|
||||||
from .const import AUTHENTICATED_USER, REQUIRES_2SA_USER, VALID_PASSWORD
|
from .const import AUTHENTICATED_USER, REQUIRES_2SA_USER, VALID_PASSWORD
|
||||||
from .const_findmyiphone import FMI_FMLY_WORKING
|
from .const_findmyiphone import FMI_FAMILY_WORKING
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
@ -103,7 +103,7 @@ class TestCmdline(TestCase):
|
||||||
])
|
])
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
|
||||||
devices = FMI_FMLY_WORKING.get("content")
|
devices = FMI_FAMILY_WORKING.get("content")
|
||||||
for device in devices:
|
for device in devices:
|
||||||
file_name = device.get("name").strip().lower() + ".fmip_snapshot"
|
file_name = device.get("name").strip().lower() + ".fmip_snapshot"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue