Beispiel #1
0
    def exchange_page_access_token(self,
                                   page_id: str,
                                   access_token: Optional[str] = None) -> str:
        """
        Get page access token by page administrator's user access token.

        Refer:
            1. https://developers.facebook.com/docs/pages/access-tokens
            2. https://developers.facebook.com/docs/facebook-login/access-tokens

        :param page_id: ID for page.
        :param access_token: Access token for user.
        :return: Page access token
        """
        if access_token is None:
            access_token = self.access_token

        resp = self._request(
            url=f"{self.version}/{page_id}",
            args={
                "fields": "access_token",
                "access_token": access_token
            },
            auth_need=False,
        )

        data = self._parse_response(resp)
        if "access_token" not in data:
            raise LibraryError({
                "message":
                "Can not get page access token. Reason maybe: \n"
                "1. Your user access token has `page_show_list` or `manage_pages` permission.\n"
                "2. You have the target page's manage permission."
            })
        return data["access_token"]
Beispiel #2
0
    def _get_oauth_session(
        self,
        redirect_uri: Optional[str] = None,
        scope: Optional[List[str]] = None,
        **kwargs,
    ) -> OAuth2Session:
        """
        :param redirect_uri: The URL that you want to redirect the person logging in back to.
        :param scope: A list of permission string to request from the person using your app.
        :param kwargs: Additional parameters for oauth.
        :return: OAuth Session
        """
        # check app credentials
        if not all([self.app_id, self.app_secret]):
            raise LibraryError({"message": "OAuth need your app credentials"})

        if redirect_uri is None:
            redirect_uri = self.DEFAULT_REDIRECT_URI
        if scope is None:
            scope = self.DEFAULT_SCOPE

        session = OAuth2Session(
            client_id=self.app_id,
            scope=scope,
            redirect_uri=redirect_uri,
            state=self.STATE,
            **kwargs,
        )
        session = facebook_compliance_fix(session)
        return session
Beispiel #3
0
    def _request(
        self,
        url: str,
        args: Optional[dict] = None,
        post_args: Optional[dict] = None,
        verb: str = "GET",
        auth_need: bool = True,
        **kwargs,
    ) -> Response:
        """
        :param url: Resource url for Graph.
        :param args: Query parameters.
        :param post_args: Form parameters.
        :param verb: HTTP method
        :param auth_need: Whether need access token.
        :param kwargs: Additional parameters.
        :return:
        """
        if auth_need:
            if verb == "GET" or verb == "DELETE":
                args = self._append_token(args=args)
            elif verb == "POST":
                post_args = self._append_token(args=post_args)

        if not url.startswith("http"):
            url = self.base_url + url

        try:
            response = self.session.request(
                method=verb,
                url=url,
                timeout=self.__timeout,
                params=args,
                data=post_args,
                proxies=self.proxies,
                **kwargs,
            )
        except requests.HTTPError as ex:
            raise LibraryError({"message": ex.args})

        # check headers
        headers = response.headers
        self.rate_limit.set_limit(headers)
        if self.sleep_on_rate_limit:
            sleep_seconds = self.rate_limit.get_sleep_seconds(
                sleep_data=self.sleep_seconds_mapping)
            time.sleep(sleep_seconds)
        return response
Beispiel #4
0
 def _parse_response(self, response: Response) -> dict:
     """
     :param response: Response from graph api.
     :return: json data
     """
     content_type = response.headers["Content-Type"]
     if "json" in content_type:
         data = response.json()
         self._check_graph_error(data=data)
         return data
     elif "image/" in content_type:
         data = {
             "data": response.content,
             "content-type": content_type,
             "url": response.url,
         }
         return data
     else:
         raise LibraryError(
             {"message": "Wrong response, not json or image"})
Beispiel #5
0
def test_error():
    error = {
        "error": {
            "message": "Message describing the error",
            "type": "OAuthException",
            "code": 190,
            "error_subcode": 460,
            "error_user_title": "A title",
            "error_user_msg": "A message",
            "fbtrace_id": "EJplcsCHuLu",
        }
    }

    fb_err = FacebookError(error)

    assert fb_err.code == 190
    assert "FacebookError" in repr(fb_err)

    error = {"message": "error message"}
    lib_err = LibraryError(error)

    assert lib_err.code == -1
    assert "LibraryError" in str(lib_err)
Beispiel #6
0
 def debug_token(self,
                 input_token: str,
                 access_token: Optional[str] = None) -> dict:
     raise LibraryError({"message": "Method not support"})
Beispiel #7
0
 def get_app_token(self,
                   app_id: Optional[str] = None,
                   app_secret: Optional[str] = None) -> dict:
     raise LibraryError({"message": "Method not support"})
Beispiel #8
0
 def exchange_long_lived_page_access_token(
         self, user_id: str, access_token: Optional[str] = None) -> dict:
     raise LibraryError({"message": "Method not support"})
Beispiel #9
0
 def exchange_page_access_token(self,
                                page_id: str,
                                access_token: Optional[str] = None) -> str:
     raise LibraryError({"message": "Method not support"})
Beispiel #10
0
    def __init__(
        self,
        app_id: Optional[str] = None,
        app_secret: Optional[str] = None,
        access_token: Optional[str] = None,
        application_only_auth: bool = False,
        oauth_flow: bool = False,
        version: Optional[str] = None,
        sleep_on_rate_limit: bool = True,
        sleep_seconds_mapping: Optional[Dict[int, int]] = None,
        base_url: Optional[str] = None,
        timeout: Optional[int] = None,
        proxies: Optional[dict] = None,
        instagram_business_id: Optional[str] = None,
    ):
        self.app_id = app_id
        self.app_secret = app_secret
        self.access_token = access_token

        self.session = requests.Session()
        self.__timeout = timeout
        self.proxies = proxies
        self.sleep_on_rate_limit = sleep_on_rate_limit
        self.sleep_seconds_mapping = self._build_sleep_seconds_resource(
            sleep_seconds_mapping=sleep_seconds_mapping)
        self.rate_limit = RateLimit()
        self.instagram_business_id = instagram_business_id

        # if provide url override
        self.base_url = self.GRAPH_URL
        if base_url is not None:
            self.base_url = base_url

        # version check
        if version is None:
            # default version is last new.
            self.version = self.VALID_API_VERSIONS[-1]
        else:
            version = str(version)
            if not version.startswith("v"):
                version = "v" + version
            version_regex = re.compile(r"^v\d*.\d{1,2}$")
            match = version_regex.search(str(version))
            if match is not None:
                if version not in self.VALID_API_VERSIONS:
                    raise LibraryError({
                        "message":
                        f"Valid API version are {','.join(self.VALID_API_VERSIONS)}"
                    })
                else:
                    self.version = version
            else:
                raise LibraryError({
                    "message":
                    f"Invalid version {version}. You can provide with like: 5.0 or v5.0"
                })

        # Token
        if access_token:
            self.access_token = access_token
        elif application_only_auth and all([self.app_id, self.app_secret]):
            data = self.get_app_token()
            self.access_token = data["access_token"]
        elif oauth_flow and all([self.app_id, self.app_secret]):
            pass
        else:
            raise LibraryError({"message": "Need access token"})