Add account creation
This commit is contained in:
pare
a29d278bf9
commit
b6692f0b16
S'han modificat 3 arxius amb 206 adicions i 3 eliminacions
|
@ -476,7 +476,71 @@ class Mastodon:
|
||||||
self.__logged_in_id = None
|
self.__logged_in_id = None
|
||||||
|
|
||||||
return response['access_token']
|
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
|
# Reading data: Instances
|
||||||
###
|
###
|
||||||
|
@ -2287,7 +2351,7 @@ class Mastodon:
|
||||||
json_object = Mastodon.__json_allow_dict_attrs(json_object)
|
json_object = Mastodon.__json_allow_dict_attrs(json_object)
|
||||||
return 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.
|
Internal API request helper.
|
||||||
"""
|
"""
|
||||||
|
@ -2314,8 +2378,10 @@ class Mastodon:
|
||||||
|
|
||||||
# Generate request headers
|
# Generate request headers
|
||||||
headers = copy.deepcopy(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
|
headers['Authorization'] = 'Bearer ' + self.access_token
|
||||||
|
if not access_token_override is None:
|
||||||
|
headers['Authorization'] = 'Bearer ' + access_token_override
|
||||||
|
|
||||||
if self.debug_requests:
|
if self.debug_requests:
|
||||||
print('Mastodon: Request to endpoint "' + endpoint + '" using method "' + method + '".')
|
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
|
from mastodon import Mastodon
|
||||||
import pytest
|
import pytest
|
||||||
import requests
|
import requests
|
||||||
|
import time
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from mock import Mock
|
from mock import Mock
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -46,3 +48,22 @@ def test_app_verify_credentials(api):
|
||||||
app = api.app_verify_credentials()
|
app = api.app_verify_credentials()
|
||||||
assert app
|
assert app
|
||||||
assert app.name == 'Mastodon.py test suite'
|
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