Skip to content

Commit

Permalink
catch all errors for check method and show user friendly message
Browse files Browse the repository at this point in the history
A few tweaks in spec
  • Loading branch information
midavadim committed Aug 30, 2023
1 parent f7b8be8 commit 47b70ca
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from airbyte_cdk.sources import AbstractSource
from airbyte_cdk.sources.streams import Stream
from airbyte_cdk.utils import AirbyteTracedException
from pydantic.error_wrappers import ValidationError
from source_facebook_marketing.api import API, FacebookAPIException
from source_facebook_marketing.spec import ConnectorConfig
from source_facebook_marketing.streams import (
Expand Down Expand Up @@ -96,10 +95,14 @@ def check_connection(self, logger: logging.Logger, config: Mapping[str, Any]) ->
"The personal ad account you're currently using is not eligible "
"for this operation. Please switch to a business ad account."
)
raise AccountTypeException(message)
return False, message

except (requests.exceptions.RequestException, ValidationError, FacebookAPIException, AccountTypeException) as e:
return False, e
except Exception as e:
if isinstance(e, AirbyteTracedException):
msg = e.message
else:
msg = repr(e)
return False, msg

# make sure that we have valid combination of "action_breakdowns" and "breakdowns" parameters
for stream in self.get_custom_insights_streams(api, config):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,21 +106,34 @@ class Config:
title = "Source Facebook Marketing"

account_id: str = Field(
title="Account ID",
title="Ad Account ID",
order=0,
description=(
"The Facebook Ad account ID to use when pulling data from the Facebook Marketing API."
" Open your Meta Ads Manager. The Ad account ID number is in the account dropdown menu or in your browser's address bar. "
"The Facebook Ad account ID to use when pulling data from the Facebook Marketing API. "
"The Ad account ID number is in the account dropdown menu or in your browser's address "
'bar of your <a href="https://adsmanager.facebook.com/adsmanager/">Meta Ads Manager</a>. '
'See the <a href="https://www.facebook.com/business/help/1492627900875762">docs</a> for more information.'
),
pattern="^[0-9]+$",
pattern_descriptor="1234567890",
examples=["111111111111111"],
)

access_token: str = Field(
title="Access Token",
order=1,
description=(
"The value of the generated access token. "
'From your App’s Dashboard, click on "Marketing API" then "Tools". '
'Select permissions <b>ads_management, ads_read, read_insights, business_management</b>. Then click on "Get token". '
'See the <a href="https://docs.airbyte.com/integrations/sources/facebook-marketing">docs</a> for more information.'
),
airbyte_secret=True,
)

start_date: datetime = Field(
title="Start Date",
order=1,
order=2,
description=(
"The date from which you'd like to replicate data for all incremental streams, "
"in the format YYYY-MM-DDT00:00:00Z. All data generated after this date will be replicated."
Expand All @@ -131,7 +144,7 @@ class Config:

end_date: Optional[datetime] = Field(
title="End Date",
order=2,
order=3,
description=(
"The date until which you'd like to replicate data for all incremental streams, in the format YYYY-MM-DDT00:00:00Z."
" All data generated between the start date and this end date will be replicated. "
Expand All @@ -142,18 +155,6 @@ class Config:
default_factory=lambda: datetime.now(tz=timezone.utc),
)

access_token: str = Field(
title="Access Token",
order=3,
description=(
"The value of the generated access token. "
'From your App’s Dashboard, click on "Marketing API" then "Tools". '
'Select permissions <b>ads_management, ads_read, read_insights, business_management</b>. Then click on "Get token". '
'See the <a href="https://docs.airbyte.com/integrations/sources/facebook-marketing">docs</a> for more information.'
),
airbyte_secret=True,
)

include_deleted: bool = Field(
title="Include Deleted Campaigns, Ads, and AdSets",
order=4,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,16 @@ def deep_merge(a: Any, b: Any) -> Any:
return a | b
else:
return a if b is None else b


def user_friendly_error_message(error_message):
print(":::::::::::::::::::::user_friendly_error_message:::::::::::::::::::::")
print(error_message)
# https://github.com/airbytehq/airbyte/issues/26679
if "Error validating access token" in error_message:
return 'config_error', "Re-authenticate to restore access or/and re-verify the Ad Account ID becuase user changed their password or Facebook has changed the session for security reasons"

elif "Missing permissions" in error_message:
return 'config_error', "Re-authenticate to restore access or/and re-verify the Ad Account ID because authenticated user no longer has access"

return '', ''
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,33 @@ def read_records(
record["thumbnail_data_url"] = fetch_thumbnail_data_url(thumbnail_url)
yield record

def read_records___(
self,
sync_mode: SyncMode,
cursor_field: List[str] = None,
stream_slice: Mapping[str, Any] = None,
stream_state: Mapping[str, Any] = None,
) -> Iterable[Mapping[str, Any]]:
"""Read with super method and append thumbnail_data_url if enabled"""
for record in self.list_objects2(params=self.request_params(stream_state=stream_state)):

if isinstance(record, AbstractObject):
yield record.export_all_data() # convert FB object to dict
else:
yield record # execute_in_batch will emmit dicts

# if self._fetch_thumbnail_images:
# thumbnail_url = record.get("thumbnail_url")
# if thumbnail_url:
# record["thumbnail_data_url"] = fetch_thumbnail_data_url(thumbnail_url)
# yield record

def list_objects(self, params: Mapping[str, Any]) -> Iterable:
return self._api.account.get_ad_creatives(params=params)

def list_objects2(self, params: Mapping[str, Any]) -> Iterable:
return self._api.account.get_ad_creatives(params=params, fields=self.fields)


class CustomConversions(FBMarketingStream):
"""doc: https://developers.facebook.com/docs/marketing-api/reference/custom-conversion"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,10 @@ def test_check_connection_invalid_config(self, api, config, logger_mock, fb_mark
def test_check_connection_exception(self, api, config, logger_mock, fb_marketing):
api.side_effect = RuntimeError("Something went wrong!")

with pytest.raises(RuntimeError, match="Something went wrong!"):
fb_marketing.check_connection(logger_mock, config=config)
ok, error_msg = fb_marketing.check_connection(logger_mock, config=config)

assert not ok
assert error_msg == "RuntimeError('Something went wrong!')"

def test_streams(self, config, api, fb_marketing):
streams = fb_marketing.streams(config)
Expand Down Expand Up @@ -159,4 +161,4 @@ def test_check_connection_account_type_exception(mocker, fb_marketing, config, l
result, error = fb_marketing.check_connection(logger=logger_mock, config=config)

assert not result
assert isinstance(error, AccountTypeException)
assert error == "The personal ad account you're currently using is not eligible for this operation. Please switch to a business ad account."

0 comments on commit 47b70ca

Please sign in to comment.