diff options
Diffstat (limited to 'mastodon/accounts.py')
-rw-r--r-- | mastodon/accounts.py | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/mastodon/accounts.py b/mastodon/accounts.py new file mode 100644 index 0000000..dcdd8de --- /dev/null +++ b/mastodon/accounts.py | |||
@@ -0,0 +1,105 @@ | |||
1 | from .defaults import _DEFAULT_SCOPES, _SCOPE_SETS | ||
2 | from .error import MastodonIllegalArgumentError, MastodonAPIError | ||
3 | from .utility import api_version | ||
4 | |||
5 | class Mastodon(): | ||
6 | @api_version("2.7.0", "2.7.0", "3.4.0") | ||
7 | def create_account(self, username, password, email, agreement=False, reason=None, locale="en", scopes=_DEFAULT_SCOPES, to_file=None, return_detailed_error=False): | ||
8 | """ | ||
9 | Creates a new user account with the given username, password and email. "agreement" | ||
10 | must be set to true (after showing the user the instance's user agreement and having | ||
11 | them agree to it), "locale" specifies the language for the confirmation email as an | ||
12 | ISO 639-1 (two letter) or, if a language does not have one, 639-3 (three letter) language | ||
13 | code. `reason` can be used to specify why a user would like to join if approved-registrations | ||
14 | mode is on. | ||
15 | |||
16 | Does not require an access token, but does require a client grant. | ||
17 | |||
18 | By default, this method is rate-limited by IP to 5 requests per 30 minutes. | ||
19 | |||
20 | Returns an access token (just like log_in), which it can also persist to to_file, | ||
21 | and sets it internally so that the user is now logged in. Note that this token | ||
22 | can only be used after the user has confirmed their email. | ||
23 | |||
24 | By default, the function will throw if the account could not be created. Alternately, | ||
25 | when `return_detailed_error` is passed, Mastodon.py will return the detailed error | ||
26 | response that the API provides (Starting from version 3.4.0 - not checked here) as an dict with | ||
27 | error details as the second return value and the token returned as `None` in case of error. | ||
28 | The dict will contain a text `error` values as well as a `details` value which is a dict with | ||
29 | one optional key for each potential field (`username`, `password`, `email` and `agreement`), | ||
30 | each if present containing a dict with an `error` category and free text `description`. | ||
31 | Valid error categories are: | ||
32 | |||
33 | * ERR_BLOCKED - When e-mail provider is not allowed | ||
34 | * ERR_UNREACHABLE - When e-mail address does not resolve to any IP via DNS (MX, A, AAAA) | ||
35 | * ERR_TAKEN - When username or e-mail are already taken | ||
36 | * ERR_RESERVED - When a username is reserved, e.g. "webmaster" or "admin" | ||
37 | * ERR_ACCEPTED - When agreement has not been accepted | ||
38 | * ERR_BLANK - When a required attribute is blank | ||
39 | * ERR_INVALID - When an attribute is malformed, e.g. wrong characters or invalid e-mail address | ||
40 | * ERR_TOO_LONG - When an attribute is over the character limit | ||
41 | * ERR_TOO_SHORT - When an attribute is under the character requirement | ||
42 | * ERR_INCLUSION - When an attribute is not one of the allowed values, e.g. unsupported locale | ||
43 | """ | ||
44 | params = self.__generate_params(locals(), ['to_file', 'scopes']) | ||
45 | params['client_id'] = self.client_id | ||
46 | params['client_secret'] = self.client_secret | ||
47 | |||
48 | if not agreement: | ||
49 | del params['agreement'] | ||
50 | |||
51 | # Step 1: Get a user-free token via oauth | ||
52 | try: | ||
53 | oauth_params = {} | ||
54 | oauth_params['scope'] = " ".join(scopes) | ||
55 | oauth_params['client_id'] = self.client_id | ||
56 | oauth_params['client_secret'] = self.client_secret | ||
57 | oauth_params['grant_type'] = 'client_credentials' | ||
58 | |||
59 | response = self.__api_request('POST', '/oauth/token', oauth_params, do_ratelimiting=False) | ||
60 | temp_access_token = response['access_token'] | ||
61 | except Exception as e: | ||
62 | raise MastodonIllegalArgumentError('Invalid request during oauth phase: %s' % e) | ||
63 | |||
64 | # Step 2: Use that to create a user | ||
65 | try: | ||
66 | response = self.__api_request('POST', '/api/v1/accounts', params, do_ratelimiting=False, access_token_override=temp_access_token, skip_error_check=True) | ||
67 | if "error" in response: | ||
68 | if return_detailed_error: | ||
69 | return None, response | ||
70 | raise MastodonIllegalArgumentError('Invalid request: %s' % e) | ||
71 | self.access_token = response['access_token'] | ||
72 | self.__set_refresh_token(response.get('refresh_token')) | ||
73 | self.__set_token_expired(int(response.get('expires_in', 0))) | ||
74 | except Exception as e: | ||
75 | raise MastodonIllegalArgumentError('Invalid request') | ||
76 | |||
77 | # Step 3: Check scopes, persist, et cetera | ||
78 | received_scopes = response["scope"].split(" ") | ||
79 | for scope_set in _SCOPE_SETS.keys(): | ||
80 | if scope_set in received_scopes: | ||
81 | received_scopes += _SCOPE_SETS[scope_set] | ||
82 | |||
83 | if not set(scopes) <= set(received_scopes): | ||
84 | raise MastodonAPIError('Granted scopes "' + " ".join(received_scopes) + '" do not contain all of the requested scopes "' + " ".join(scopes) + '".') | ||
85 | |||
86 | if to_file is not None: | ||
87 | with open(to_file, 'w') as token_file: | ||
88 | token_file.write(response['access_token'] + "\n") | ||
89 | token_file.write(self.api_base_url + "\n") | ||
90 | |||
91 | self.__logged_in_id = None | ||
92 | |||
93 | if return_detailed_error: | ||
94 | return response['access_token'], {} | ||
95 | else: | ||
96 | return response['access_token'] | ||
97 | |||
98 | @api_version("3.4.0", "3.4.0", "3.4.0") | ||
99 | def email_resend_confirmation(self): | ||
100 | """ | ||
101 | Requests a re-send of the users confirmation mail for an unconfirmed logged in user. | ||
102 | |||
103 | Only available to the app that the user originally signed up with. | ||
104 | """ | ||
105 | self.__api_request('POST', '/api/v1/emails/confirmations') | ||