diff --git a/.gitignore b/.gitignore index cd194d8e..9afbd2bb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.pyc +.venv MANIFEST dist build diff --git a/facebook_business/__init__.py b/facebook_business/__init__.py index c066f236..d0c71ddd 100644 --- a/facebook_business/__init__.py +++ b/facebook_business/__init__.py @@ -21,7 +21,7 @@ from facebook_business.session import FacebookSession from facebook_business.api import FacebookAdsApi -__version__ = '17.0.2' +__version__ = '2023.08.14' __all__ = [ 'session', 'objects', diff --git a/facebook_business/adobjects/adaccount.py b/facebook_business/adobjects/adaccount.py index 8e29750b..5df06852 100644 --- a/facebook_business/adobjects/adaccount.py +++ b/facebook_business/adobjects/adaccount.py @@ -4037,6 +4037,53 @@ def delete_users_of_any_audience(self, fields=None, params=None, batch=None, suc self.assure_call() return request.execute() + # -------------------------- + # Mayple additions - start + # -------------------------- + + class PermittedTasks: + advertise = 'ADVERTISE' + analyze = 'ANALYZE' + draft = 'DRAFT' + manage = 'MANAGE' + + def create_agency(self, fields=None, params=None, batch=None, success=None, failure=None, pending=False): + from facebook_business.utils import api_utils + if batch is None and (success is not None or failure is not None): + api_utils.warning('`success` and `failure` callback only work for batch call.') + param_types = { + 'business': 'string', + 'permitted_tasks': 'list', + } + enums = { + 'permitted_tasks_enum': AdAccount.PermittedTasks.__dict__.values(), + } + request = FacebookRequest( + node_id=self['id'], + method='POST', + endpoint='/agencies', + api=self._api, + param_checker=TypeChecker(param_types, enums), + target_class=AdAccount, + api_type='EDGE', + response_parser=ObjectParser(target_class=AdAccount, api=self._api), + ) + request.add_params(params) + request.add_fields(fields) + + if batch is not None: + request.add_to_batch(batch, success=success, failure=failure) + return request + elif pending: + return request + else: + self.assure_call() + return request.execute() + + # ------------------------ + # Mayple additions - end + # ------------------------ + _field_types = { 'account_id': 'string', 'account_status': 'unsigned int', diff --git a/facebook_business/adobjects/page.py b/facebook_business/adobjects/page.py index 5c17896b..3745ada6 100644 --- a/facebook_business/adobjects/page.py +++ b/facebook_business/adobjects/page.py @@ -4754,6 +4754,129 @@ def get_welcome_message_flows(self, fields=None, params=None, batch=None, succes self.assure_call() return request.execute() + def create_work_page_message(self, fields=None, params=None, batch=None, success=None, failure=None, pending=False): + from facebook_business.utils import api_utils + if batch is None and (success is not None or failure is not None): + api_utils.warning('`success` and `failure` callback only work for batch call.') + param_types = { + 'message': 'Object', + 'messaging_type': 'messaging_type_enum', + 'notification_type': 'notification_type_enum', + 'payload': 'string', + 'persona_id': 'string', + 'recipient': 'Object', + 'sender_action': 'sender_action_enum', + 'tag': 'Object', + } + enums = { + 'messaging_type_enum': Page.MessagingType.__dict__.values(), + 'notification_type_enum': Page.NotificationType.__dict__.values(), + 'sender_action_enum': Page.SenderAction.__dict__.values(), + } + request = FacebookRequest( + node_id=self['id'], + method='POST', + endpoint='/workpagemessages', + api=self._api, + param_checker=TypeChecker(param_types, enums), + target_class=Page, + api_type='EDGE', + response_parser=ObjectParser(target_class=Page, api=self._api), + ) + request.add_params(params) + request.add_fields(fields) + + if batch is not None: + request.add_to_batch(batch, success=success, failure=failure) + return request + elif pending: + return request + else: + self.assure_call() + return request.execute() + + # -------------------------- + # Mayple additions - start + # -------------------------- + + def get_extended_access_token(self, fields=None, params=None, batch=None, pending=False): + param_types = { + 'grant_type': 'string', + 'client_id': 'string', + 'client_secret': 'string', + 'fb_exchange_token': 'string', + } + enums = { + } + request = FacebookRequest( + node_id='oauth', + method='GET', + endpoint='/access_token', + api=self._api, + param_checker=TypeChecker(param_types, enums), + target_class=AbstractCrudObject, + api_type='NODE', + response_parser=ObjectParser(reuse_object=self), + ) + + # TODO: Create an actual object instead of using AbstractCrudObject with this list.. + request._accepted_fields = list(request._accepted_fields) + request._accepted_fields.extend([ + 'access_token', 'token_type' + ]) + + request.add_params(params) + request.add_fields(fields) + + if batch is not None: + request.add_to_batch(batch) + return request + elif pending: + return request + else: + self.assure_call() + return request.execute() + + def get_access_token_debug_details(self, fields=None, params=None, batch=None, pending=False): + param_types = { + 'input_token': 'string', + 'access_token': 'string', + } + enums = { + } + request = FacebookRequest( + node_id='debug_token', + method='GET', + endpoint='/', + api=self._api, + param_checker=TypeChecker(param_types, enums), + target_class=AbstractCrudObject, + api_type='NODE', + response_parser=ObjectParser(reuse_object=self), + ) + + # TODO: Create an actual object instead of using AbstractCrudObject with this list.. + request._accepted_fields = list(request._accepted_fields) + request._accepted_fields.extend([ + 'app_id', 'application', 'expires_at', 'is_valid', 'issued_at', 'scopes', 'user_id' + ]) + + request.add_params(params) + request.add_fields(fields) + + if batch is not None: + request.add_to_batch(batch) + return request + elif pending: + return request + else: + self.assure_call() + return request.execute() + + # ------------------------ + # Mayple additions - end + # ------------------------ + _field_types = { 'about': 'string', 'access_token': 'string', diff --git a/facebook_business/adobjects/profilepicturesource.py b/facebook_business/adobjects/profilepicturesource.py index f3395861..cc4dec64 100644 --- a/facebook_business/adobjects/profilepicturesource.py +++ b/facebook_business/adobjects/profilepicturesource.py @@ -49,9 +49,12 @@ class Field(AbstractObject.Field): width = 'width' class Type: - album = 'album' - small = 'small' thumbnail = 'thumbnail' + small = 'small' + normal = 'normal' + album = 'album' + large = 'large' + square = 'square' class BreakingChange: profile_picture = 'PROFILE_PICTURE' diff --git a/facebook_business/adobjects/user.py b/facebook_business/adobjects/user.py index 61ad0de4..7f65fa63 100644 --- a/facebook_business/adobjects/user.py +++ b/facebook_business/adobjects/user.py @@ -2226,6 +2226,123 @@ def create_video(self, fields=None, params=None, batch=None, success=None, failu self.assure_call() return request.execute() + # -------------------------- + # Mayple additions - start + # -------------------------- + + def create_business(self, fields=None, params=None, batch=None, pending=False): + from facebook_business.adobjects.business import Business + + param_types = { + 'name': 'string', + 'vertical': 'vertical_enum', + 'primary_page': 'int', + 'timezone_id': 'unsigned int', + } + enums = { + 'vertical_enum': Business.Vertical.__dict__.values(), + } + request = FacebookRequest( + node_id=self['id'], + method='POST', + endpoint='/businesses', + api=self._api, + param_checker=TypeChecker(param_types, enums), + target_class=Business, + api_type='EDGE', + response_parser=ObjectParser(target_class=Business, api=self._api), + ) + request.add_params(params) + request.add_fields(fields) + + if batch is not None: + request.add_to_batch(batch) + return request + elif pending: + return request + else: + self.assure_call() + return request.execute() + + def get_extended_access_token(self, fields=None, params=None, batch=None, pending=False): + param_types = { + 'grant_type': 'string', + 'client_id': 'string', + 'client_secret': 'string', + 'fb_exchange_token': 'string', + } + enums = { + } + request = FacebookRequest( + node_id='oauth', + method='GET', + endpoint='/access_token', + api=self._api, + param_checker=TypeChecker(param_types, enums), + target_class=AbstractCrudObject, + api_type='NODE', + response_parser=ObjectParser(reuse_object=self), + ) + + # TODO: Create an actual object instead of using AbstractCrudObject with this list.. + request._accepted_fields = list(request._accepted_fields) + request._accepted_fields.extend([ + 'access_token', 'token_type' + ]) + + request.add_params(params) + request.add_fields(fields) + + if batch is not None: + request.add_to_batch(batch) + return request + elif pending: + return request + else: + self.assure_call() + return request.execute() + + def get_access_token_debug_details(self, fields=None, params=None, batch=None, pending=False): + param_types = { + 'input_token': 'string', + 'access_token': 'string', + } + enums = { + } + request = FacebookRequest( + node_id='debug_token', + method='GET', + endpoint='/', + api=self._api, + param_checker=TypeChecker(param_types, enums), + target_class=AbstractCrudObject, + api_type='NODE', + response_parser=ObjectParser(reuse_object=self), + ) + + # TODO: Create an actual object instead of using AbstractCrudObject with this list.. + request._accepted_fields = list(request._accepted_fields) + request._accepted_fields.extend([ + 'app_id', 'application', 'expires_at', 'is_valid', 'issued_at', 'scopes', 'user_id', 'type', + 'profile_id' + ]) + + request.add_params(params) + request.add_fields(fields) + + if batch is not None: + request.add_to_batch(batch) + return request + elif pending: + return request + else: + self.assure_call() + return request.execute() + + # ------------------------ + # Mayple additions - end + # ------------------------ + _field_types = { 'about': 'string', 'age_range': 'AgeRange', diff --git a/facebook_business/api.py b/facebook_business/api.py index 7ab9a97e..c5788321 100644 --- a/facebook_business/api.py +++ b/facebook_business/api.py @@ -689,7 +689,19 @@ def execute(self): if response.error(): raise response.error() if self._response_parser: - return self._response_parser.parse_single(response.json()) + try: + return self._response_parser.parse_single(response.json()) + except TypeError as te: + if "string indices must be integers" in str(te): + raise FacebookRequestError( + "Erroneous response from Facebook API", + response._call, + response.status(), + response.headers(), + response.body(), + ) + else: + raise else: return response diff --git a/facebook_business/apiconfig.py b/facebook_business/apiconfig.py index 98c1360b..a7beef0f 100644 --- a/facebook_business/apiconfig.py +++ b/facebook_business/apiconfig.py @@ -20,6 +20,6 @@ ads_api_config = { 'API_VERSION': 'v17.0', - 'SDK_VERSION': 'v17.0.2', + 'SDK_VERSION': 'v2023.08.14', 'STRICT_MODE': False } diff --git a/setup.py b/setup.py index 1606c64a..fb5d4bc5 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ requirements_filename = os.path.join(this_dir, 'requirements.txt') PACKAGE_NAME = 'facebook_business' -PACKAGE_VERSION = '17.0.3' +PACKAGE_VERSION = '2023.08.14' PACKAGE_AUTHOR = 'Facebook' PACKAGE_AUTHOR_EMAIL = '' PACKAGE_URL = 'https://github.com/facebook/facebook-python-business-sdk'