diff options
Diffstat (limited to 'mastodon')
-rw-r--r-- | mastodon/Mastodon.py | 106 |
1 files changed, 63 insertions, 43 deletions
diff --git a/mastodon/Mastodon.py b/mastodon/Mastodon.py index 12a054a..ae560c5 100644 --- a/mastodon/Mastodon.py +++ b/mastodon/Mastodon.py | |||
@@ -605,8 +605,7 @@ class Mastodon: | |||
605 | params['scope'] = " ".join(scopes) | 605 | params['scope'] = " ".join(scopes) |
606 | 606 | ||
607 | try: | 607 | try: |
608 | response = self.__api_request( | 608 | response = self.__api_request('POST', '/oauth/token', params, do_ratelimiting=False) |
609 | 'POST', '/oauth/token', params, do_ratelimiting=False) | ||
610 | self.access_token = response['access_token'] | 609 | self.access_token = response['access_token'] |
611 | self.__set_refresh_token(response.get('refresh_token')) | 610 | self.__set_refresh_token(response.get('refresh_token')) |
612 | self.__set_token_expired(int(response.get('expires_in', 0))) | 611 | self.__set_token_expired(int(response.get('expires_in', 0))) |
@@ -658,8 +657,8 @@ class Mastodon: | |||
658 | self.access_token = None | 657 | self.access_token = None |
659 | self.__logged_in_id = None | 658 | self.__logged_in_id = None |
660 | 659 | ||
661 | @api_version("2.7.0", "2.7.0", "2.7.0") | 660 | @api_version("2.7.0", "2.7.0", "3.4.0") |
662 | def create_account(self, username, password, email, agreement=False, reason=None, locale="en", scopes=__DEFAULT_SCOPES, to_file=None): | 661 | def create_account(self, username, password, email, agreement=False, reason=None, locale="en", scopes=__DEFAULT_SCOPES, to_file=None, return_detailed_error=False): |
663 | """ | 662 | """ |
664 | Creates a new user account with the given username, password and email. "agreement" | 663 | Creates a new user account with the given username, password and email. "agreement" |
665 | must be set to true (after showing the user the instance's user agreement and having | 664 | must be set to true (after showing the user the instance's user agreement and having |
@@ -674,6 +673,26 @@ class Mastodon: | |||
674 | Returns an access token (just like log_in), which it can also persist to to_file, | 673 | Returns an access token (just like log_in), which it can also persist to to_file, |
675 | and sets it internally so that the user is now logged in. Note that this token | 674 | and sets it internally so that the user is now logged in. Note that this token |
676 | can only be used after the user has confirmed their email. | 675 | can only be used after the user has confirmed their email. |
676 | |||
677 | By default, the function will throw if the account could not be created. Alternately, | ||
678 | when `return_detailed_error` is passed, Mastodon.py will return the detailed error | ||
679 | response that the API provides (Starting from version 3.4.0 - not checked here) as an dict with | ||
680 | error details as the second return value and the token returned as `None` in case of error. | ||
681 | The dict will contain a text `error` values as well as a `details` value which is a dict with | ||
682 | one optional key for each potential field (`username`, `password`, `email` and `agreement`), | ||
683 | each if present containing a dict with an `error` category and free text `description`. | ||
684 | Valid error categories are: | ||
685 | |||
686 | * ERR_BLOCKED - When e-mail provider is not allowed | ||
687 | * ERR_UNREACHABLE - When e-mail address does not resolve to any IP via DNS (MX, A, AAAA) | ||
688 | * ERR_TAKEN - When username or e-mail are already taken | ||
689 | * ERR_RESERVED - When a username is reserved, e.g. "webmaster" or "admin" | ||
690 | * ERR_ACCEPTED - When agreement has not been accepted | ||
691 | * ERR_BLANK - When a required attribute is blank | ||
692 | * ERR_INVALID - When an attribute is malformed, e.g. wrong characters or invalid e-mail address | ||
693 | * ERR_TOO_LONG - When an attribute is over the character limit | ||
694 | * ERR_TOO_SHORT - When an attribute is under the character requirement | ||
695 | * ERR_INCLUSION - When an attribute is not one of the allowed values, e.g. unsupported locale | ||
677 | """ | 696 | """ |
678 | params = self.__generate_params(locals(), ['to_file', 'scopes']) | 697 | params = self.__generate_params(locals(), ['to_file', 'scopes']) |
679 | params['client_id'] = self.client_id | 698 | params['client_id'] = self.client_id |
@@ -690,8 +709,7 @@ class Mastodon: | |||
690 | oauth_params['client_secret'] = self.client_secret | 709 | oauth_params['client_secret'] = self.client_secret |
691 | oauth_params['grant_type'] = 'client_credentials' | 710 | oauth_params['grant_type'] = 'client_credentials' |
692 | 711 | ||
693 | response = self.__api_request( | 712 | response = self.__api_request('POST', '/oauth/token', oauth_params, do_ratelimiting=False) |
694 | 'POST', '/oauth/token', oauth_params, do_ratelimiting=False) | ||
695 | temp_access_token = response['access_token'] | 713 | temp_access_token = response['access_token'] |
696 | except Exception as e: | 714 | except Exception as e: |
697 | raise MastodonIllegalArgumentError( | 715 | raise MastodonIllegalArgumentError( |
@@ -699,13 +717,16 @@ class Mastodon: | |||
699 | 717 | ||
700 | # Step 2: Use that to create a user | 718 | # Step 2: Use that to create a user |
701 | try: | 719 | try: |
702 | response = self.__api_request('POST', '/api/v1/accounts', params, do_ratelimiting=False, | 720 | response = self.__api_request('POST', '/api/v1/accounts', params, do_ratelimiting=False, access_token_override=temp_access_token, skip_error_check=True) |
703 | access_token_override=temp_access_token) | 721 | if "error" in response: |
722 | if return_detailed_error: | ||
723 | return None, response | ||
724 | raise MastodonIllegalArgumentError('Invalid request: %s' % e) | ||
704 | self.access_token = response['access_token'] | 725 | self.access_token = response['access_token'] |
705 | self.__set_refresh_token(response.get('refresh_token')) | 726 | self.__set_refresh_token(response.get('refresh_token')) |
706 | self.__set_token_expired(int(response.get('expires_in', 0))) | 727 | self.__set_token_expired(int(response.get('expires_in', 0))) |
707 | except Exception as e: | 728 | except Exception as e: |
708 | raise MastodonIllegalArgumentError('Invalid request: %s' % e) | 729 | raise MastodonIllegalArgumentError('Invalid request') |
709 | 730 | ||
710 | # Step 3: Check scopes, persist, et cetera | 731 | # Step 3: Check scopes, persist, et cetera |
711 | received_scopes = response["scope"].split(" ") | 732 | received_scopes = response["scope"].split(" ") |
@@ -714,8 +735,7 @@ class Mastodon: | |||
714 | received_scopes += self.__SCOPE_SETS[scope_set] | 735 | received_scopes += self.__SCOPE_SETS[scope_set] |
715 | 736 | ||
716 | if not set(scopes) <= set(received_scopes): | 737 | if not set(scopes) <= set(received_scopes): |
717 | raise MastodonAPIError( | 738 | raise MastodonAPIError('Granted scopes "' + " ".join(received_scopes) + '" do not contain all of the requested scopes "' + " ".join(scopes) + '".') |
718 | 'Granted scopes "' + " ".join(received_scopes) + '" do not contain all of the requested scopes "' + " ".join(scopes) + '".') | ||
719 | 739 | ||
720 | if to_file is not None: | 740 | if to_file is not None: |
721 | with open(to_file, 'w') as token_file: | 741 | with open(to_file, 'w') as token_file: |
@@ -724,7 +744,10 @@ class Mastodon: | |||
724 | 744 | ||
725 | self.__logged_in_id = None | 745 | self.__logged_in_id = None |
726 | 746 | ||
727 | return response['access_token'] | 747 | if return_detailed_error: |
748 | return response['access_token'], {} | ||
749 | else: | ||
750 | return response['access_token'] | ||
728 | 751 | ||
729 | @api_version("3.4.0", "3.4.0", "3.4.0") | 752 | @api_version("3.4.0", "3.4.0", "3.4.0") |
730 | def email_resend_confirmation(self): | 753 | def email_resend_confirmation(self): |
@@ -2775,7 +2798,7 @@ class Mastodon: | |||
2775 | """ | 2798 | """ |
2776 | if not policy in ['all', 'none', 'follower', 'followed']: | 2799 | if not policy in ['all', 'none', 'follower', 'followed']: |
2777 | raise MastodonIllegalArgumentError("Valid values for policy are 'all', 'none', 'follower' or 'followed'.") | 2800 | raise MastodonIllegalArgumentError("Valid values for policy are 'all', 'none', 'follower' or 'followed'.") |
2778 | 2801 | ||
2779 | endpoint = Mastodon.__protocolize(endpoint) | 2802 | endpoint = Mastodon.__protocolize(endpoint) |
2780 | 2803 | ||
2781 | push_pubkey_b64 = base64.b64encode(encrypt_params['pubkey']) | 2804 | push_pubkey_b64 = base64.b64encode(encrypt_params['pubkey']) |
@@ -3506,7 +3529,7 @@ class Mastodon: | |||
3506 | isotime = isotime[:-2] + ":" + isotime[-2:] | 3529 | isotime = isotime[:-2] + ":" + isotime[-2:] |
3507 | return isotime | 3530 | return isotime |
3508 | 3531 | ||
3509 | def __api_request(self, method, endpoint, params={}, files={}, headers={}, access_token_override=None, base_url_override=None, do_ratelimiting=True, use_json=False, parse=True, return_response_object=False): | 3532 | def __api_request(self, method, endpoint, params={}, files={}, headers={}, access_token_override=None, base_url_override=None, do_ratelimiting=True, use_json=False, parse=True, return_response_object=False, skip_error_check=False): |
3510 | """ | 3533 | """ |
3511 | Internal API request helper. | 3534 | Internal API request helper. |
3512 | """ | 3535 | """ |
@@ -3657,35 +3680,32 @@ class Mastodon: | |||
3657 | time.sleep(to_next) | 3680 | time.sleep(to_next) |
3658 | request_complete = False | 3681 | request_complete = False |
3659 | continue | 3682 | continue |
3683 | |||
3684 | if skip_error_check == False: | ||
3685 | if response_object.status_code == 404: | ||
3686 | ex_type = MastodonNotFoundError | ||
3687 | if not error_msg: | ||
3688 | error_msg = 'Endpoint not found.' | ||
3689 | # this is for compatibility with older versions | ||
3690 | # which raised MastodonAPIError('Endpoint not found.') | ||
3691 | # on any 404 | ||
3692 | elif response_object.status_code == 401: | ||
3693 | ex_type = MastodonUnauthorizedError | ||
3694 | elif response_object.status_code == 500: | ||
3695 | ex_type = MastodonInternalServerError | ||
3696 | elif response_object.status_code == 502: | ||
3697 | ex_type = MastodonBadGatewayError | ||
3698 | elif response_object.status_code == 503: | ||
3699 | ex_type = MastodonServiceUnavailableError | ||
3700 | elif response_object.status_code == 504: | ||
3701 | ex_type = MastodonGatewayTimeoutError | ||
3702 | elif response_object.status_code >= 500 and \ | ||
3703 | response_object.status_code <= 511: | ||
3704 | ex_type = MastodonServerError | ||
3705 | else: | ||
3706 | ex_type = MastodonAPIError | ||
3660 | 3707 | ||
3661 | if response_object.status_code == 404: | 3708 | raise ex_type('Mastodon API returned error', response_object.status_code, response_object.reason, error_msg) |
3662 | ex_type = MastodonNotFoundError | ||
3663 | if not error_msg: | ||
3664 | error_msg = 'Endpoint not found.' | ||
3665 | # this is for compatibility with older versions | ||
3666 | # which raised MastodonAPIError('Endpoint not found.') | ||
3667 | # on any 404 | ||
3668 | elif response_object.status_code == 401: | ||
3669 | ex_type = MastodonUnauthorizedError | ||
3670 | elif response_object.status_code == 500: | ||
3671 | ex_type = MastodonInternalServerError | ||
3672 | elif response_object.status_code == 502: | ||
3673 | ex_type = MastodonBadGatewayError | ||
3674 | elif response_object.status_code == 503: | ||
3675 | ex_type = MastodonServiceUnavailableError | ||
3676 | elif response_object.status_code == 504: | ||
3677 | ex_type = MastodonGatewayTimeoutError | ||
3678 | elif response_object.status_code >= 500 and \ | ||
3679 | response_object.status_code <= 511: | ||
3680 | ex_type = MastodonServerError | ||
3681 | else: | ||
3682 | ex_type = MastodonAPIError | ||
3683 | |||
3684 | raise ex_type( | ||
3685 | 'Mastodon API returned error', | ||
3686 | response_object.status_code, | ||
3687 | response_object.reason, | ||
3688 | error_msg) | ||
3689 | 3709 | ||
3690 | if return_response_object: | 3710 | if return_response_object: |
3691 | return response_object | 3711 | return response_object |