Add account creation
This commit is contained in:
pare
a29d278bf9
commit
b6692f0b16
S'han modificat 3 arxius amb 206 adicions i 3 eliminacions
|
@ -477,6 +477,70 @@ class Mastodon:
|
|||
|
||||
return response['access_token']
|
||||
|
||||
@api_version("2.7.0", "2.7.0", "2.7.0")
|
||||
def create_account(self, username, password, email, agreement=False, locale="en", scopes=__DEFAULT_SCOPES, to_file=None):
|
||||
"""
|
||||
Creates a new user account with the given username, password and email. "agreement"
|
||||
must be set to true (after showing the user the instances user agreement and having
|
||||
them agree to it), "locale" specifies the language for the confirmation e-mail as an
|
||||
ISO 639-1 (two-letter) language code.
|
||||
|
||||
Does not require an access token, but does require a client grant.
|
||||
|
||||
By default, this method is rate-limited by IP to 5 requests per 30 minutes.
|
||||
|
||||
Returns an access token (just like log_in), which it can also persist to to_file,
|
||||
and sets it internally so that the user is now logged in. Note that this token
|
||||
can only be used after the user has confirmed their e-mail.
|
||||
"""
|
||||
params = self.__generate_params(locals(), ['to_file', 'scopes'])
|
||||
params['client_id'] = self.client_id
|
||||
params['client_secret'] = self.client_secret
|
||||
|
||||
if agreement == False:
|
||||
del params_initial['agreement']
|
||||
|
||||
# Step 1: Get a user-free token via oauth
|
||||
try:
|
||||
oauth_params = {}
|
||||
oauth_params['scope'] = " ".join(scopes)
|
||||
oauth_params['client_id'] = self.client_id
|
||||
oauth_params['client_secret'] = self.client_secret
|
||||
oauth_params['grant_type'] = 'client_credentials'
|
||||
|
||||
response = self.__api_request('POST', '/oauth/token', oauth_params, do_ratelimiting=False)
|
||||
temp_access_token = response['access_token']
|
||||
except Exception as e:
|
||||
raise MastodonIllegalArgumentError('Invalid request during oauth phase: %s' % e)
|
||||
|
||||
# Step 2: Use that to create a user
|
||||
try:
|
||||
response = self.__api_request('POST', '/api/v1/accounts', params, do_ratelimiting=False,
|
||||
access_token_override = temp_access_token)
|
||||
self.access_token = response['access_token']
|
||||
self.__set_refresh_token(response.get('refresh_token'))
|
||||
self.__set_token_expired(int(response.get('expires_in', 0)))
|
||||
except Exception as e:
|
||||
raise MastodonIllegalArgumentError('Invalid request: %s' % e)
|
||||
|
||||
# Step 3: Check scopes, persist, et cetera
|
||||
received_scopes = response["scope"].split(" ")
|
||||
for scope_set in self.__SCOPE_SETS.keys():
|
||||
if scope_set in received_scopes:
|
||||
received_scopes += self.__SCOPE_SETS[scope_set]
|
||||
|
||||
if not set(scopes) <= set(received_scopes):
|
||||
raise MastodonAPIError(
|
||||
'Granted scopes "' + " ".join(received_scopes) + '" do not contain all of the requested scopes "' + " ".join(scopes) + '".')
|
||||
|
||||
if to_file is not None:
|
||||
with open(to_file, 'w') as token_file:
|
||||
token_file.write(response['access_token'] + '\n')
|
||||
|
||||
self.__logged_in_id = None
|
||||
|
||||
return response['access_token']
|
||||
|
||||
###
|
||||
# Reading data: Instances
|
||||
###
|
||||
|
@ -2287,7 +2351,7 @@ class Mastodon:
|
|||
json_object = Mastodon.__json_allow_dict_attrs(json_object)
|
||||
return json_object
|
||||
|
||||
def __api_request(self, method, endpoint, params={}, files={}, headers={}, do_ratelimiting=True):
|
||||
def __api_request(self, method, endpoint, params={}, files={}, headers={}, access_token_override=None, do_ratelimiting=True):
|
||||
"""
|
||||
Internal API request helper.
|
||||
"""
|
||||
|
@ -2314,8 +2378,10 @@ class Mastodon:
|
|||
|
||||
# Generate request headers
|
||||
headers = copy.deepcopy(headers)
|
||||
if self.access_token is not None:
|
||||
if not self.access_token is None:
|
||||
headers['Authorization'] = 'Bearer ' + self.access_token
|
||||
if not access_token_override is None:
|
||||
headers['Authorization'] = 'Bearer ' + access_token_override
|
||||
|
||||
if self.debug_requests:
|
||||
print('Mastodon: Request to endpoint "' + endpoint + '" using method "' + method + '".')
|
||||
|
|
116
tests/cassettes/test_app_account_create.yaml
Normal file
116
tests/cassettes/test_app_account_create.yaml
Normal file
|
@ -0,0 +1,116 @@
|
|||
interactions:
|
||||
- request:
|
||||
body: client_name=mastodon.py+generated+test+app&scopes=read+write+follow+push&redirect_uris=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob
|
||||
headers:
|
||||
Accept: ['*/*']
|
||||
Accept-Encoding: ['gzip, deflate']
|
||||
Connection: [keep-alive]
|
||||
Content-Length: ['122']
|
||||
Content-Type: [application/x-www-form-urlencoded]
|
||||
User-Agent: [python-requests/2.18.4]
|
||||
method: POST
|
||||
uri: http://localhost:3000/api/v1/apps
|
||||
response:
|
||||
body: {string: '{"id":"17","name":"mastodon.py generated test app","website":null,"redirect_uri":"urn:ietf:wg:oauth:2.0:oob","client_id":"6b8b07698f3f57d73b0fd779fac2fcc64d6e852d3334425a6b50b53bc32db986","client_secret":"df903d79cc8a27d8d4f9aa8213cf65a9681fea679a56643fcb3e5a3f66c4f9c7","vapid_key":"BCryMB_mKFcSpmXE3kJ1Ri3ZFVdBLjRsX54VYhE21BMyftx8k67qWxFs2OCuQCtj0k1ILESkQhGuOKJcQnodx4g="}'}
|
||||
headers:
|
||||
Cache-Control: ['max-age=0, private, must-revalidate']
|
||||
Content-Type: [application/json; charset=utf-8]
|
||||
ETag: [W/"3a06e1b620ce8b2c3ce4045d1e2c179b"]
|
||||
Referrer-Policy: [strict-origin-when-cross-origin]
|
||||
Transfer-Encoding: [chunked]
|
||||
Vary: ['Accept-Encoding, Origin']
|
||||
X-Content-Type-Options: [nosniff]
|
||||
X-Download-Options: [noopen]
|
||||
X-Frame-Options: [SAMEORIGIN]
|
||||
X-Permitted-Cross-Domain-Policies: [none]
|
||||
X-Request-Id: [258ec6bb-4a82-41c3-b55b-560fdfb5ad13]
|
||||
X-Runtime: ['0.025005']
|
||||
X-XSS-Protection: [1; mode=block]
|
||||
content-length: ['374']
|
||||
status: {code: 200, message: OK}
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept: ['*/*']
|
||||
Accept-Encoding: ['gzip, deflate']
|
||||
Connection: [keep-alive]
|
||||
User-Agent: [python-requests/2.18.4]
|
||||
method: GET
|
||||
uri: http://localhost:3000/api/v1/instance/
|
||||
response:
|
||||
body: {string: '{"uri":"localhost","title":"Mastodon","description":"","email":"","version":"2.8.0","urls":{"streaming_api":"ws://localhost:4000"},"stats":{"user_count":2,"status_count":15,"domain_count":0},"thumbnail":"http://localhost/packs/media/images/preview-9a17d32fc48369e8ccd910a75260e67d.jpg","languages":["en"],"registrations":true,"contact_account":null}'}
|
||||
headers:
|
||||
Cache-Control: ['max-age=300, public']
|
||||
Content-Type: [application/json; charset=utf-8]
|
||||
Date: ['Sun, 28 Apr 2019 15:56:05 GMT']
|
||||
ETag: [W/"4ba18203af6a9d9402c05e8ffc21ac45"]
|
||||
Referrer-Policy: [strict-origin-when-cross-origin]
|
||||
Transfer-Encoding: [chunked]
|
||||
Vary: ['Accept-Encoding, Origin']
|
||||
X-Content-Type-Options: [nosniff]
|
||||
X-Download-Options: [noopen]
|
||||
X-Frame-Options: [SAMEORIGIN]
|
||||
X-Permitted-Cross-Domain-Policies: [none]
|
||||
X-Request-Id: [bfb330d1-53c3-4fcc-b79e-30e256a2f845]
|
||||
X-Runtime: ['0.025590']
|
||||
X-XSS-Protection: [1; mode=block]
|
||||
content-length: ['349']
|
||||
status: {code: 200, message: OK}
|
||||
- request:
|
||||
body: scope=read+write+follow+push&client_id=6b8b07698f3f57d73b0fd779fac2fcc64d6e852d3334425a6b50b53bc32db986&client_secret=df903d79cc8a27d8d4f9aa8213cf65a9681fea679a56643fcb3e5a3f66c4f9c7&grant_type=client_credentials
|
||||
headers:
|
||||
Accept: ['*/*']
|
||||
Accept-Encoding: ['gzip, deflate']
|
||||
Connection: [keep-alive]
|
||||
Content-Length: ['212']
|
||||
Content-Type: [application/x-www-form-urlencoded]
|
||||
User-Agent: [python-requests/2.18.4]
|
||||
method: POST
|
||||
uri: http://localhost:3000/oauth/token
|
||||
response:
|
||||
body: {string: '{"access_token":"756276912d1d5d74cfbf2e275517a234cee584891ca1f87a3fb2bdbd1fed1ca1","token_type":"Bearer","scope":"read
|
||||
write follow push","created_at":1556466966}'}
|
||||
headers:
|
||||
Cache-Control: ['private, no-store']
|
||||
Content-Type: [application/json; charset=utf-8]
|
||||
ETag: [W/"851cc791f71c2ce9bf821e023e26b361"]
|
||||
Pragma: [no-cache]
|
||||
Transfer-Encoding: [chunked]
|
||||
Vary: ['Accept-Encoding, Origin']
|
||||
X-Request-Id: [0205c26b-9c77-4c32-bb59-a2d69eafde33]
|
||||
X-Runtime: ['0.039194']
|
||||
content-length: ['162']
|
||||
status: {code: 200, message: OK}
|
||||
- request:
|
||||
body: locale=en&agreement=1&email=email%40localhost11707&password=swordfish&username=coolguy11707&client_id=6b8b07698f3f57d73b0fd779fac2fcc64d6e852d3334425a6b50b53bc32db986&client_secret=df903d79cc8a27d8d4f9aa8213cf65a9681fea679a56643fcb3e5a3f66c4f9c7
|
||||
headers:
|
||||
Accept: ['*/*']
|
||||
Accept-Encoding: ['gzip, deflate']
|
||||
Authorization: [Bearer 756276912d1d5d74cfbf2e275517a234cee584891ca1f87a3fb2bdbd1fed1ca1]
|
||||
Connection: [keep-alive]
|
||||
Content-Length: ['245']
|
||||
Content-Type: [application/x-www-form-urlencoded]
|
||||
User-Agent: [python-requests/2.18.4]
|
||||
method: POST
|
||||
uri: http://localhost:3000/api/v1/accounts
|
||||
response:
|
||||
body: {string: '{"access_token":"b20f513163b154065d17f5aff37b779f51d13c152fe6e7d1be366d64d2e74e39","token_type":"Bearer","scope":"read
|
||||
write follow push","created_at":1556466966}'}
|
||||
headers:
|
||||
Cache-Control: ['private, no-store']
|
||||
Content-Type: [application/json; charset=utf-8]
|
||||
ETag: [W/"7ba50c22bb330ba5a0936c19bea78093"]
|
||||
Pragma: [no-cache]
|
||||
Referrer-Policy: [strict-origin-when-cross-origin]
|
||||
Transfer-Encoding: [chunked]
|
||||
Vary: ['Accept-Encoding, Origin']
|
||||
X-Content-Type-Options: [nosniff]
|
||||
X-Download-Options: [noopen]
|
||||
X-Frame-Options: [SAMEORIGIN]
|
||||
X-Permitted-Cross-Domain-Policies: [none]
|
||||
X-Request-Id: [51ac5a4c-e850-46be-89c6-681e46f891dd]
|
||||
X-Runtime: ['0.208778']
|
||||
X-XSS-Protection: [1; mode=block]
|
||||
content-length: ['162']
|
||||
status: {code: 200, message: OK}
|
||||
version: 1
|
|
@ -1,6 +1,8 @@
|
|||
from mastodon import Mastodon
|
||||
import pytest
|
||||
import requests
|
||||
import time
|
||||
|
||||
try:
|
||||
from mock import Mock
|
||||
except ImportError:
|
||||
|
@ -46,3 +48,22 @@ def test_app_verify_credentials(api):
|
|||
app = api.app_verify_credentials()
|
||||
assert app
|
||||
assert app.name == 'Mastodon.py test suite'
|
||||
|
||||
@pytest.mark.vcr()
|
||||
def test_app_account_create():
|
||||
# This leaves behind stuff on the test server, which is unfortunate, but eh.
|
||||
suffix = str(time.time()).replace(".", "")[-5:]
|
||||
|
||||
test_app = test_app = Mastodon.create_app(
|
||||
"mastodon.py generated test app",
|
||||
api_base_url="http://localhost:3000/"
|
||||
)
|
||||
|
||||
test_app_api = Mastodon(
|
||||
test_app[0],
|
||||
test_app[1],
|
||||
api_base_url="http://localhost:3000/"
|
||||
)
|
||||
test_token = test_app_api.create_account("coolguy" + suffix, "swordfish", "email@localhost" + suffix, agreement=True)
|
||||
assert test_token
|
||||
|
||||
|
|
Loading…
Referencia en una nova incidència