API - refacto + remove unused endpoint for now
This commit is contained in:
parent
dfe50b5287
commit
b5b4ac8f92
@ -5,7 +5,7 @@ from flask import Flask
|
|||||||
import fittrackee
|
import fittrackee
|
||||||
from fittrackee.users.models import User
|
from fittrackee.users.models import User
|
||||||
|
|
||||||
from ..api_test_case import ApiTestCaseMixin
|
from ..mixins import ApiTestCaseMixin
|
||||||
|
|
||||||
|
|
||||||
class TestGetConfig(ApiTestCaseMixin):
|
class TestGetConfig(ApiTestCaseMixin):
|
||||||
|
@ -7,7 +7,7 @@ from fittrackee import email_service
|
|||||||
from fittrackee.emails.email import EmailMessage
|
from fittrackee.emails.email import EmailMessage
|
||||||
from fittrackee.emails.exceptions import InvalidEmailUrlScheme
|
from fittrackee.emails.exceptions import InvalidEmailUrlScheme
|
||||||
|
|
||||||
from ..api_test_case import CallArgsMixin
|
from ..mixins import CallArgsMixin
|
||||||
from .template_results.password_reset_request import expected_en_text_body
|
from .template_results.password_reset_request import expected_en_text_body
|
||||||
|
|
||||||
|
|
||||||
|
6
fittrackee/tests/fixtures/fixtures_emails.py
vendored
6
fittrackee/tests/fixtures/fixtures_emails.py
vendored
@ -30,6 +30,12 @@ def user_password_change_email_mock() -> Iterator[MagicMock]:
|
|||||||
yield mock
|
yield mock
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def reset_password_email() -> Iterator[MagicMock]:
|
||||||
|
with patch('fittrackee.users.auth.reset_password_email') as mock:
|
||||||
|
yield mock
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def user_reset_password_email() -> Iterator[MagicMock]:
|
def user_reset_password_email() -> Iterator[MagicMock]:
|
||||||
with patch('fittrackee.users.users.reset_password_email') as mock:
|
with patch('fittrackee.users.users.reset_password_email') as mock:
|
||||||
|
4
fittrackee/tests/fixtures/fixtures_users.py
vendored
4
fittrackee/tests/fixtures/fixtures_users.py
vendored
@ -60,7 +60,7 @@ def user_1_paris() -> User:
|
|||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def user_2() -> User:
|
def user_2() -> User:
|
||||||
user = User(username='toto', email='toto@toto.com', password='87654321')
|
user = User(username='toto', email='toto@toto.com', password='12345678')
|
||||||
db.session.add(user)
|
db.session.add(user)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return user
|
return user
|
||||||
@ -68,7 +68,7 @@ def user_2() -> User:
|
|||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def user_2_admin() -> User:
|
def user_2_admin() -> User:
|
||||||
user = User(username='toto', email='toto@toto.com', password='87654321')
|
user = User(username='toto', email='toto@toto.com', password='12345678')
|
||||||
user.admin = True
|
user.admin = True
|
||||||
db.session.add(user)
|
db.session.add(user)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -6,25 +6,35 @@ from flask.testing import FlaskClient
|
|||||||
from werkzeug.test import TestResponse
|
from werkzeug.test import TestResponse
|
||||||
|
|
||||||
from .custom_asserts import assert_errored_response
|
from .custom_asserts import assert_errored_response
|
||||||
|
from .utils import random_email, random_string
|
||||||
|
|
||||||
|
|
||||||
class ApiTestCaseMixin:
|
class RandomMixin:
|
||||||
|
@staticmethod
|
||||||
|
def random_string(
|
||||||
|
length: Optional[int] = None,
|
||||||
|
prefix: Optional[str] = None,
|
||||||
|
suffix: Optional[str] = None,
|
||||||
|
) -> str:
|
||||||
|
return random_string(length, prefix, suffix)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def random_email() -> str:
|
||||||
|
return random_email()
|
||||||
|
|
||||||
|
|
||||||
|
class ApiTestCaseMixin(RandomMixin):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_test_client_and_auth_token(
|
def get_test_client_and_auth_token(
|
||||||
app: Flask, user_email: str
|
app: Flask, user_email: str
|
||||||
) -> Tuple[FlaskClient, str]:
|
) -> Tuple[FlaskClient, str]:
|
||||||
"""user_email must be user_1 or user_2 email"""
|
|
||||||
client = app.test_client()
|
client = app.test_client()
|
||||||
resp_login = client.post(
|
resp_login = client.post(
|
||||||
'/api/auth/login',
|
'/api/auth/login',
|
||||||
data=json.dumps(
|
data=json.dumps(
|
||||||
dict(
|
dict(
|
||||||
email=user_email,
|
email=user_email,
|
||||||
password=(
|
password='12345678',
|
||||||
'87654321'
|
|
||||||
if user_email == 'toto@toto.com'
|
|
||||||
else '12345678'
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
content_type='application/json',
|
content_type='application/json',
|
File diff suppressed because it is too large
Load Diff
@ -6,11 +6,10 @@ from unittest.mock import MagicMock, patch
|
|||||||
from flask import Flask
|
from flask import Flask
|
||||||
|
|
||||||
from fittrackee.users.models import User, UserSportPreference
|
from fittrackee.users.models import User, UserSportPreference
|
||||||
from fittrackee.users.utils.random import random_string
|
|
||||||
from fittrackee.utils import get_readable_duration
|
from fittrackee.utils import get_readable_duration
|
||||||
from fittrackee.workouts.models import Sport, Workout
|
from fittrackee.workouts.models import Sport, Workout
|
||||||
|
|
||||||
from ..api_test_case import ApiTestCaseMixin
|
from ..mixins import ApiTestCaseMixin
|
||||||
|
|
||||||
|
|
||||||
class TestGetUser(ApiTestCaseMixin):
|
class TestGetUser(ApiTestCaseMixin):
|
||||||
@ -1108,7 +1107,7 @@ class TestUpdateUser(ApiTestCaseMixin):
|
|||||||
response = client.patch(
|
response = client.patch(
|
||||||
f'/api/users/{user_2.username}',
|
f'/api/users/{user_2.username}',
|
||||||
content_type='application/json',
|
content_type='application/json',
|
||||||
data=json.dumps(dict(new_email=random_string())),
|
data=json.dumps(dict(new_email=self.random_string())),
|
||||||
headers=dict(Authorization=f'Bearer {auth_token}'),
|
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1128,7 +1127,7 @@ class TestUpdateUser(ApiTestCaseMixin):
|
|||||||
client.patch(
|
client.patch(
|
||||||
f'/api/users/{user_2.username}',
|
f'/api/users/{user_2.username}',
|
||||||
content_type='application/json',
|
content_type='application/json',
|
||||||
data=json.dumps(dict(new_email=random_string())),
|
data=json.dumps(dict(new_email=self.random_string())),
|
||||||
headers=dict(Authorization=f'Bearer {auth_token}'),
|
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1166,7 +1165,7 @@ class TestUpdateUser(ApiTestCaseMixin):
|
|||||||
app, user_1_admin.email
|
app, user_1_admin.email
|
||||||
)
|
)
|
||||||
new_email = 'new.' + user_2.email
|
new_email = 'new.' + user_2.email
|
||||||
expected_token = random_string()
|
expected_token = self.random_string()
|
||||||
|
|
||||||
with patch('secrets.token_urlsafe', return_value=expected_token):
|
with patch('secrets.token_urlsafe', return_value=expected_token):
|
||||||
response = client.patch(
|
response = client.patch(
|
||||||
|
@ -3,6 +3,7 @@ from unittest.mock import patch
|
|||||||
import pytest
|
import pytest
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
|
|
||||||
|
from fittrackee.tests.utils import random_string
|
||||||
from fittrackee.users.exceptions import UserNotFoundException
|
from fittrackee.users.exceptions import UserNotFoundException
|
||||||
from fittrackee.users.models import User
|
from fittrackee.users.models import User
|
||||||
from fittrackee.users.utils.admin import set_admin_rights
|
from fittrackee.users.utils.admin import set_admin_rights
|
||||||
@ -12,7 +13,6 @@ from fittrackee.users.utils.controls import (
|
|||||||
is_valid_email,
|
is_valid_email,
|
||||||
register_controls,
|
register_controls,
|
||||||
)
|
)
|
||||||
from fittrackee.users.utils.random import random_string
|
|
||||||
|
|
||||||
|
|
||||||
class TestSetAdminRights:
|
class TestSetAdminRights:
|
||||||
|
25
fittrackee/tests/utils.py
Normal file
25
fittrackee/tests/utils.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import random
|
||||||
|
import string
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
def random_string(
|
||||||
|
length: Optional[int] = None,
|
||||||
|
prefix: Optional[str] = None,
|
||||||
|
suffix: Optional[str] = None,
|
||||||
|
) -> str:
|
||||||
|
if length is None:
|
||||||
|
length = 10
|
||||||
|
random_str = ''.join(
|
||||||
|
random.choice(string.ascii_letters + string.digits)
|
||||||
|
for _ in range(length)
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
f'{"" if prefix is None else prefix}'
|
||||||
|
f'{random_str}'
|
||||||
|
f'{"" if suffix is None else suffix}'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def random_email() -> str:
|
||||||
|
return random_string(suffix='@example.com')
|
@ -5,7 +5,7 @@ from flask import Flask
|
|||||||
from fittrackee.users.models import User
|
from fittrackee.users.models import User
|
||||||
from fittrackee.workouts.models import Sport, Workout
|
from fittrackee.workouts.models import Sport, Workout
|
||||||
|
|
||||||
from ..api_test_case import ApiTestCaseMixin
|
from ..mixins import ApiTestCaseMixin
|
||||||
|
|
||||||
|
|
||||||
class TestGetRecords(ApiTestCaseMixin):
|
class TestGetRecords(ApiTestCaseMixin):
|
||||||
|
@ -6,7 +6,7 @@ from fittrackee import db
|
|||||||
from fittrackee.users.models import User, UserSportPreference
|
from fittrackee.users.models import User, UserSportPreference
|
||||||
from fittrackee.workouts.models import Sport, Workout
|
from fittrackee.workouts.models import Sport, Workout
|
||||||
|
|
||||||
from ..api_test_case import ApiTestCaseMixin
|
from ..mixins import ApiTestCaseMixin
|
||||||
|
|
||||||
expected_sport_1_cycling_result = {
|
expected_sport_1_cycling_result = {
|
||||||
'id': 1,
|
'id': 1,
|
||||||
|
@ -5,7 +5,7 @@ from flask import Flask
|
|||||||
from fittrackee.users.models import User
|
from fittrackee.users.models import User
|
||||||
from fittrackee.workouts.models import Sport, Workout
|
from fittrackee.workouts.models import Sport, Workout
|
||||||
|
|
||||||
from ..api_test_case import ApiTestCaseMixin
|
from ..mixins import ApiTestCaseMixin
|
||||||
|
|
||||||
|
|
||||||
class TestGetStatsByTime(ApiTestCaseMixin):
|
class TestGetStatsByTime(ApiTestCaseMixin):
|
||||||
|
@ -7,7 +7,7 @@ from flask import Flask
|
|||||||
from fittrackee.users.models import User
|
from fittrackee.users.models import User
|
||||||
from fittrackee.workouts.models import Sport, Workout
|
from fittrackee.workouts.models import Sport, Workout
|
||||||
|
|
||||||
from ..api_test_case import ApiTestCaseMixin
|
from ..mixins import ApiTestCaseMixin
|
||||||
from .utils import get_random_short_id
|
from .utils import get_random_short_id
|
||||||
|
|
||||||
|
|
||||||
@ -73,19 +73,13 @@ class TestGetWorkouts(ApiTestCaseMixin):
|
|||||||
workout_cycling_user_1: Workout,
|
workout_cycling_user_1: Workout,
|
||||||
workout_running_user_1: Workout,
|
workout_running_user_1: Workout,
|
||||||
) -> None:
|
) -> None:
|
||||||
client = app.test_client()
|
client, auth_token = self.get_test_client_and_auth_token(
|
||||||
resp_login = client.post(
|
app, user_2.email
|
||||||
'/api/auth/login',
|
|
||||||
data=json.dumps(dict(email='toto@toto.com', password='87654321')),
|
|
||||||
content_type='application/json',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
response = client.get(
|
response = client.get(
|
||||||
'/api/workouts',
|
'/api/workouts',
|
||||||
headers=dict(
|
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||||
Authorization='Bearer '
|
|
||||||
+ json.loads(resp_login.data.decode())['auth_token']
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
data = json.loads(response.data.decode())
|
data = json.loads(response.data.decode())
|
||||||
|
@ -12,7 +12,7 @@ from fittrackee.users.models import User
|
|||||||
from fittrackee.workouts.models import Sport, Workout
|
from fittrackee.workouts.models import Sport, Workout
|
||||||
from fittrackee.workouts.utils.short_id import decode_short_id
|
from fittrackee.workouts.utils.short_id import decode_short_id
|
||||||
|
|
||||||
from ..api_test_case import ApiTestCaseMixin, CallArgsMixin
|
from ..mixins import ApiTestCaseMixin, CallArgsMixin
|
||||||
|
|
||||||
|
|
||||||
def assert_workout_data_with_gpx(data: Dict) -> None:
|
def assert_workout_data_with_gpx(data: Dict) -> None:
|
||||||
@ -1018,18 +1018,13 @@ class TestPostAndGetWorkoutWithGpx(ApiTestCaseMixin):
|
|||||||
)
|
)
|
||||||
data = json.loads(response.data.decode())
|
data = json.loads(response.data.decode())
|
||||||
workout_short_id = data['data']['workouts'][0]['id']
|
workout_short_id = data['data']['workouts'][0]['id']
|
||||||
|
client, auth_token = self.get_test_client_and_auth_token(
|
||||||
resp_login = client.post(
|
app, user_2.email
|
||||||
'/api/auth/login',
|
|
||||||
data=json.dumps(dict(email='toto@toto.com', password='87654321')),
|
|
||||||
content_type='application/json',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
response = client.get(
|
response = client.get(
|
||||||
f'/api/workouts/{workout_short_id}/chart_data',
|
f'/api/workouts/{workout_short_id}/chart_data',
|
||||||
headers=dict(
|
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||||
Authorization='Bearer '
|
|
||||||
+ json.loads(resp_login.data.decode())['auth_token']
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assert_403(response)
|
self.assert_403(response)
|
||||||
|
@ -8,7 +8,7 @@ from flask import Flask
|
|||||||
from fittrackee.users.models import User
|
from fittrackee.users.models import User
|
||||||
from fittrackee.workouts.models import Sport, Workout
|
from fittrackee.workouts.models import Sport, Workout
|
||||||
|
|
||||||
from ..api_test_case import ApiTestCaseMixin
|
from ..mixins import ApiTestCaseMixin
|
||||||
from .utils import get_random_short_id, post_an_workout
|
from .utils import get_random_short_id, post_an_workout
|
||||||
|
|
||||||
|
|
||||||
@ -152,21 +152,15 @@ class TestEditWorkoutWithGpx(ApiTestCaseMixin):
|
|||||||
gpx_file: str,
|
gpx_file: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
_, workout_short_id = post_an_workout(app, gpx_file)
|
_, workout_short_id = post_an_workout(app, gpx_file)
|
||||||
client = app.test_client()
|
client, auth_token = self.get_test_client_and_auth_token(
|
||||||
resp_login = client.post(
|
app, user_2.email
|
||||||
'/api/auth/login',
|
|
||||||
data=json.dumps(dict(email='toto@toto.com', password='87654321')),
|
|
||||||
content_type='application/json',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
response = client.patch(
|
response = client.patch(
|
||||||
f'/api/workouts/{workout_short_id}',
|
f'/api/workouts/{workout_short_id}',
|
||||||
content_type='application/json',
|
content_type='application/json',
|
||||||
data=json.dumps(dict(sport_id=2, title="Workout test")),
|
data=json.dumps(dict(sport_id=2, title="Workout test")),
|
||||||
headers=dict(
|
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||||
Authorization='Bearer '
|
|
||||||
+ json.loads(resp_login.data.decode())['auth_token']
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assert_403(response)
|
self.assert_403(response)
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import json
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
@ -7,7 +6,7 @@ from fittrackee.files import get_absolute_file_path
|
|||||||
from fittrackee.users.models import User
|
from fittrackee.users.models import User
|
||||||
from fittrackee.workouts.models import Sport, Workout
|
from fittrackee.workouts.models import Sport, Workout
|
||||||
|
|
||||||
from ..api_test_case import ApiTestCaseMixin
|
from ..mixins import ApiTestCaseMixin
|
||||||
from .utils import get_random_short_id, post_an_workout
|
from .utils import get_random_short_id, post_an_workout
|
||||||
|
|
||||||
|
|
||||||
@ -39,19 +38,13 @@ class TestDeleteWorkoutWithGpx(ApiTestCaseMixin):
|
|||||||
gpx_file: str,
|
gpx_file: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
_, workout_short_id = post_an_workout(app, gpx_file)
|
_, workout_short_id = post_an_workout(app, gpx_file)
|
||||||
client = app.test_client()
|
client, auth_token = self.get_test_client_and_auth_token(
|
||||||
resp_login = client.post(
|
app, user_2.email
|
||||||
'/api/auth/login',
|
|
||||||
data=json.dumps(dict(email='toto@toto.com', password='87654321')),
|
|
||||||
content_type='application/json',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
response = client.delete(
|
response = client.delete(
|
||||||
f'/api/workouts/{workout_short_id}',
|
f'/api/workouts/{workout_short_id}',
|
||||||
headers=dict(
|
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||||
Authorization='Bearer '
|
|
||||||
+ json.loads(resp_login.data.decode())['auth_token']
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assert_403(response)
|
self.assert_403(response)
|
||||||
@ -113,18 +106,13 @@ class TestDeleteWorkoutWithoutGpx(ApiTestCaseMixin):
|
|||||||
sport_1_cycling: Sport,
|
sport_1_cycling: Sport,
|
||||||
workout_cycling_user_1: Workout,
|
workout_cycling_user_1: Workout,
|
||||||
) -> None:
|
) -> None:
|
||||||
client = app.test_client()
|
client, auth_token = self.get_test_client_and_auth_token(
|
||||||
resp_login = client.post(
|
app, user_2.email
|
||||||
'/api/auth/login',
|
|
||||||
data=json.dumps(dict(email='toto@toto.com', password='87654321')),
|
|
||||||
content_type='application/json',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
response = client.delete(
|
response = client.delete(
|
||||||
f'/api/workouts/{workout_cycling_user_1.short_id}',
|
f'/api/workouts/{workout_cycling_user_1.short_id}',
|
||||||
headers=dict(
|
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||||
Authorization='Bearer '
|
|
||||||
+ json.loads(resp_login.data.decode())['auth_token']
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assert_403(response)
|
self.assert_403(response)
|
||||||
|
@ -227,67 +227,6 @@ def login_user() -> Union[Dict, HttpResponse]:
|
|||||||
return handle_error_and_return_response(e, db=db)
|
return handle_error_and_return_response(e, db=db)
|
||||||
|
|
||||||
|
|
||||||
@auth_blueprint.route('/auth/logout', methods=['GET'])
|
|
||||||
@authenticate
|
|
||||||
def logout_user(auth_user: User) -> Union[Dict, HttpResponse]:
|
|
||||||
"""
|
|
||||||
user logout
|
|
||||||
|
|
||||||
**Example request**:
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
GET /api/auth/logout HTTP/1.1
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
**Example responses**:
|
|
||||||
|
|
||||||
- successful logout
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
HTTP/1.1 200 OK
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"message": "successfully logged out",
|
|
||||||
"status": "success"
|
|
||||||
}
|
|
||||||
|
|
||||||
- error on login
|
|
||||||
|
|
||||||
.. sourcecode:: http
|
|
||||||
|
|
||||||
HTTP/1.1 401 UNAUTHORIZED
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"message": "provide a valid auth token",
|
|
||||||
"status": "error"
|
|
||||||
}
|
|
||||||
|
|
||||||
:reqheader Authorization: OAuth 2.0 Bearer Token
|
|
||||||
|
|
||||||
:statuscode 200: successfully logged out
|
|
||||||
:statuscode 401: provide a valid auth token
|
|
||||||
|
|
||||||
"""
|
|
||||||
# get auth token
|
|
||||||
auth_header = request.headers.get('Authorization')
|
|
||||||
if not auth_header:
|
|
||||||
return UnauthorizedErrorResponse('provide a valid auth token')
|
|
||||||
|
|
||||||
auth_token = auth_header.split(' ')[1]
|
|
||||||
resp = User.decode_auth_token(auth_token)
|
|
||||||
if isinstance(resp, str):
|
|
||||||
return UnauthorizedErrorResponse(resp)
|
|
||||||
|
|
||||||
return {
|
|
||||||
'status': 'success',
|
|
||||||
'message': 'successfully logged out',
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@auth_blueprint.route('/auth/profile', methods=['GET'])
|
@auth_blueprint.route('/auth/profile', methods=['GET'])
|
||||||
@authenticate
|
@authenticate
|
||||||
def get_authenticated_user_profile(
|
def get_authenticated_user_profile(
|
||||||
|
@ -31,7 +31,6 @@ from .decorators import authenticate, authenticate_as_admin
|
|||||||
from .exceptions import UserNotFoundException
|
from .exceptions import UserNotFoundException
|
||||||
from .models import User, UserSportPreference
|
from .models import User, UserSportPreference
|
||||||
from .utils.admin import set_admin_rights
|
from .utils.admin import set_admin_rights
|
||||||
from .utils.random import random_string
|
|
||||||
|
|
||||||
users_blueprint = Blueprint('users', __name__)
|
users_blueprint = Blueprint('users', __name__)
|
||||||
|
|
||||||
@ -514,7 +513,7 @@ def update_user(auth_user: User, user_name: str) -> Union[Dict, HttpResponse]:
|
|||||||
'reset_password' in user_data
|
'reset_password' in user_data
|
||||||
and user_data['reset_password'] is True
|
and user_data['reset_password'] is True
|
||||||
):
|
):
|
||||||
new_password = random_string(length=random.randint(10, 20))
|
new_password = secrets.token_urlsafe(random.randint(16, 20))
|
||||||
user.password = bcrypt.generate_password_hash(
|
user.password = bcrypt.generate_password_hash(
|
||||||
new_password, current_app.config.get('BCRYPT_LOG_ROUNDS')
|
new_password, current_app.config.get('BCRYPT_LOG_ROUNDS')
|
||||||
).decode()
|
).decode()
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
import random
|
|
||||||
import string
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
|
|
||||||
def random_string(length: Optional[int] = None) -> str:
|
|
||||||
if length is None:
|
|
||||||
length = 10
|
|
||||||
return ''.join(
|
|
||||||
random.choice(string.ascii_letters + string.digits)
|
|
||||||
for _ in range(length)
|
|
||||||
)
|
|
Loading…
Reference in New Issue
Block a user