API - init user account activation

This commit is contained in:
Sam
2022-03-19 22:02:06 +01:00
parent b5b4ac8f92
commit a1f80e9745
26 changed files with 1334 additions and 67 deletions

View File

@@ -9,17 +9,12 @@ from ..mixins import ApiTestCaseMixin
class TestGetConfig(ApiTestCaseMixin):
def test_it_gets_application_config(
self, app: Flask, user_1: User
def test_it_gets_application_config_for_unauthenticated_user(
self, app: Flask
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email
)
client = app.test_client()
response = client.get(
'/api/config',
headers=dict(Authorization=f'Bearer {auth_token}'),
)
response = client.get('/api/config')
data = json.loads(response.data.decode())
assert response.status_code == 200
@@ -36,6 +31,22 @@ class TestGetConfig(ApiTestCaseMixin):
)
assert data['data']['version'] == fittrackee.__version__
def test_it_gets_application_config(
self, app: Flask, user_1: User
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email
)
response = client.get(
'/api/config',
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
def test_it_returns_error_if_application_has_no_config(
self, app_no_config: Flask, user_1_admin: User
) -> None:

View File

@@ -0,0 +1,174 @@
# flake8: noqa
expected_en_text_body = """Hi test,
You have created an account on FitTrackee account. Use the link below to confirm your address email.
Verify your email: http://localhost/account-confirmation?token=xxx
For security, this request was received from a Linux device using Firefox.
If this account creation wasn't initiated by you, please ignore this email.
Thanks,
The FitTrackee Team
http://localhost"""
expected_fr_text_body = """Bonjour test,
Vous avez créé un sur FitTrackee.
Cliquez sur le lien ci-dessous pour confirmer votre adresse email.
Vérifier l'adresse email : http://localhost/account-confirmation?token=xxx
Pour vérification, cette demande a été reçue à partir d'un appareil sous Linux, utilisant le navigateur Firefox.
Si vous n'êtes pas à l'origine de la création de ce compte, vous pouvez ignorer cet e-mail.
Merci,
L'équipe FitTrackee
http://localhost"""
expected_en_html_body = """ <body>
<span class="preheader">Use this link to confirm your account.</span>
<table class="email-wrapper" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td align="center">
<table class="email-content" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td class="email-masthead">
<a href="http://localhost" class="f-fallback email-masthead-name">
FitTrackee
</a>
</td>
</tr>
<tr>
<td class="email-body" width="100%" cellpadding="0" cellspacing="0">
<table class="email-body-inner" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td class="content-cell">
<div class="f-fallback">
<h1>Hi test,</h1>
<p>You have created an account on FitTrackee account. Use the link below to confirm your address email.</p>
<table class="body-action" align="center" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td align="center">
<table width="100%" border="0" cellspacing="0" cellpadding="0" role="presentation">
<tr>
<td align="center">
<a href="http://localhost/account-confirmation?token=xxx" class="f-fallback button button--green" target="_blank">Verify your email</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<p>
For security, this request was received from a Linux device using Firefox.
If this account creation wasn't initiated by you, please ignore this email.
</p>
<p>Thanks,
<br>The FitTrackee Team</p>
<table class="body-sub" role="presentation">
<tr>
<td>
<p class="f-fallback sub">If youre having trouble with the button above, copy and paste the URL below into your web browser.</p>
<p class="f-fallback sub">http://localhost/account-confirmation?token=xxx</p>
</td>
</tr>
</table>
</div>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table class="email-footer" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td class="content-cell" align="center">
<p class="f-fallback sub align-center">&copy; FitTrackee.</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>"""
expected_fr_html_body = """ <body>
<span class="preheader">Utiliser ce lien pour confirmer votre inscription.</span>
<table class="email-wrapper" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td align="center">
<table class="email-content" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td class="email-masthead">
<a href="http://localhost" class="f-fallback email-masthead-name">
FitTrackee
</a>
</td>
</tr>
<tr>
<td class="email-body" width="100%" cellpadding="0" cellspacing="0">
<table class="email-body-inner" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td class="content-cell">
<div class="f-fallback">
<h1>Bonjour test,</h1>
<p>Vous avez créé un sur FitTrackee.
Cliquez sur le lien ci-dessous pour confirmer votre adresse email.
</p>
<table class="body-action" align="center" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td align="center">
<table width="100%" border="0" cellspacing="0" cellpadding="0" role="presentation">
<tr>
<td align="center">
<a href="http://localhost/account-confirmation?token=xxx" class="f-fallback button button--green" target="_blank">Vérifier l'adresse email</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<p>
Pour vérification, cette demande a été reçue à partir d'un appareil sous Linux, utilisant le navigateur Firefox.
Si vous n'êtes pas à l'origine de la création de ce compte, vous pouvez ignorer cet e-mail.
</p>
<p>Merci,
<br>L'équipe FitTrackee</p>
<table class="body-sub" role="presentation">
<tr>
<td>
<p class="f-fallback sub">Si vous avez des problèmes avec le bouton, vous pouvez copier et coller le lien suivant dans votre navigateur</p>
<p class="f-fallback sub">http://localhost/account-confirmation?token=xxx</p>
</td>
</tr>
</table>
</div>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table class="email-footer" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td class="content-cell" align="center">
<p class="f-fallback sub align-center">&copy; FitTrackee.</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>"""

View File

@@ -0,0 +1,77 @@
import pytest
from flask import Flask
from fittrackee.emails.email import EmailTemplate
from .template_results.email_account_confirmation import (
expected_en_html_body,
expected_en_text_body,
expected_fr_html_body,
expected_fr_text_body,
)
class TestEmailTemplateForAccountConfirmation:
EMAIL_DATA = {
'username': 'test',
'account_confirmation_url': (
'http://localhost/account-confirmation?token=xxx'
),
'operating_system': 'Linux',
'browser_name': 'Firefox',
'fittrackee_url': 'http://localhost',
}
@pytest.mark.parametrize(
'lang, expected_subject',
[
('en', 'FitTrackee - Confirm your account'),
('fr', 'FitTrackee - Confirmer votre inscription'),
],
)
def test_it_gets_subject(
self, app: Flask, lang: str, expected_subject: str
) -> None:
email_template = EmailTemplate(app.config['TEMPLATES_FOLDER'])
subject = email_template.get_content(
'account_confirmation', lang, 'subject.txt', {}
)
assert subject == expected_subject
@pytest.mark.parametrize(
'lang, expected_text_body',
[
('en', expected_en_text_body),
('fr', expected_fr_text_body),
],
)
def test_it_gets_text_body(
self, app: Flask, lang: str, expected_text_body: str
) -> None:
email_template = EmailTemplate(app.config['TEMPLATES_FOLDER'])
text_body = email_template.get_content(
'account_confirmation', lang, 'body.txt', self.EMAIL_DATA
)
assert text_body == expected_text_body
def test_it_gets_en_html_body(self, app: Flask) -> None:
email_template = EmailTemplate(app.config['TEMPLATES_FOLDER'])
text_body = email_template.get_content(
'account_confirmation', 'en', 'body.html', self.EMAIL_DATA
)
assert expected_en_html_body in text_body
def test_it_gets_fr_html_body(self, app: Flask) -> None:
email_template = EmailTemplate(app.config['TEMPLATES_FOLDER'])
text_body = email_template.get_content(
'account_confirmation', 'fr', 'body.html', self.EMAIL_DATA
)
assert expected_fr_html_body in text_body

View File

@@ -46,3 +46,9 @@ def user_reset_password_email() -> Iterator[MagicMock]:
def user_email_updated_to_new_address_mock() -> Iterator[MagicMock]:
with patch('fittrackee.users.users.email_updated_to_new_address') as mock:
yield mock
@pytest.fixture()
def account_confirmation_email_mock() -> Iterator[MagicMock]:
with patch('fittrackee.users.auth.account_confirmation_email') as mock:
yield mock

View File

@@ -10,6 +10,7 @@ from fittrackee.workouts.models import Sport
@pytest.fixture()
def user_1() -> User:
user = User(username='test', email='test@test.com', password='12345678')
user.is_active = True
db.session.add(user)
db.session.commit()
return user
@@ -18,6 +19,7 @@ def user_1() -> User:
@pytest.fixture()
def user_1_upper() -> User:
user = User(username='TEST', email='TEST@TEST.COM', password='12345678')
user.is_active = True
db.session.add(user)
db.session.commit()
return user
@@ -29,6 +31,7 @@ def user_1_admin() -> User:
username='admin', email='admin@example.com', password='12345678'
)
admin.admin = True
admin.is_active = True
db.session.add(admin)
db.session.commit()
return admin
@@ -44,6 +47,7 @@ def user_1_full() -> User:
user.language = 'en'
user.timezone = 'America/New_York'
user.birth_date = datetime.datetime.strptime('01/01/1980', '%d/%m/%Y')
user.is_active = True
db.session.add(user)
db.session.commit()
return user
@@ -53,6 +57,7 @@ def user_1_full() -> User:
def user_1_paris() -> User:
user = User(username='test', email='test@test.com', password='12345678')
user.timezone = 'Europe/Paris'
user.is_active = True
db.session.add(user)
db.session.commit()
return user
@@ -61,6 +66,7 @@ def user_1_paris() -> User:
@pytest.fixture()
def user_2() -> User:
user = User(username='toto', email='toto@toto.com', password='12345678')
user.is_active = True
db.session.add(user)
db.session.commit()
return user
@@ -69,6 +75,7 @@ def user_2() -> User:
@pytest.fixture()
def user_2_admin() -> User:
user = User(username='toto', email='toto@toto.com', password='12345678')
user.is_active = True
user.admin = True
db.session.add(user)
db.session.commit()
@@ -78,12 +85,23 @@ def user_2_admin() -> User:
@pytest.fixture()
def user_3() -> User:
user = User(username='sam', email='sam@test.com', password='12345678')
user.is_active = True
user.weekm = True
db.session.add(user)
db.session.commit()
return user
@pytest.fixture()
def inactive_user() -> User:
user = User(
username='inactive', email='inactive@example.com', password='12345678'
)
db.session.add(user)
db.session.commit()
return user
@pytest.fixture()
def user_sport_1_preference(
user_1: User, sport_1_cycling: Sport

View File

@@ -53,7 +53,10 @@ class ApiTestCaseMixin(RandomMixin):
)
@staticmethod
def assert_401(response: TestResponse, error_message: str) -> Dict:
def assert_401(
response: TestResponse,
error_message: Optional[str] = 'provide a valid auth token',
) -> Dict:
return assert_errored_response(
response, 401, error_message=error_message
)

View File

@@ -123,7 +123,7 @@ class TestUserRegistration(ApiTestCaseMixin):
content_type='application/json',
)
self.assert_400(response, 'sorry, that user already exists')
self.assert_400(response, 'sorry, that username is already taken')
def test_it_returns_error_if_password_is_missing(self, app: Flask) -> None:
client = app.test_client()
@@ -193,11 +193,111 @@ class TestUserRegistration(ApiTestCaseMixin):
self.assert_400(response, 'email: valid email must be provided\n')
def test_it_does_not_send_email_after_error(
self, app: Flask, account_confirmation_email_mock: Mock
) -> None:
client = app.test_client()
client.post(
'/api/auth/register',
data=json.dumps(
dict(
username=self.random_string(),
email=self.random_string(),
)
),
content_type='application/json',
)
account_confirmation_email_mock.send.assert_not_called()
def test_it_returns_success_if_payload_is_valid(self, app: Flask) -> None:
client = app.test_client()
response = client.post(
'/api/auth/register',
data=json.dumps(
dict(
username=self.random_string(),
email=self.random_email(),
password=self.random_string(),
)
),
content_type='application/json',
)
assert response.status_code == 200
assert response.content_type == 'application/json'
data = json.loads(response.data.decode())
assert data['status'] == 'success'
assert 'auth_token' not in data
def test_it_creates_user_with_inactive_account(self, app: Flask) -> None:
client = app.test_client()
username = self.random_string()
email = self.random_email()
client.post(
'/api/auth/register',
data=json.dumps(
dict(
username=username,
email=email,
password=self.random_string(),
)
),
content_type='application/json',
)
new_user = User.query.filter_by(username=username).first()
assert new_user.email == email
assert new_user.password is not None
assert new_user.is_active is False
def test_it_calls_account_confirmation_email_if_payload_is_valid(
self, app: Flask, account_confirmation_email_mock: Mock
) -> None:
client = app.test_client()
email = self.random_email()
username = self.random_string()
expected_token = self.random_string()
with patch('secrets.token_urlsafe', return_value=expected_token):
client.post(
'/api/auth/register',
data=json.dumps(
dict(
username=username,
email=email,
password='12345678',
)
),
content_type='application/json',
environ_base={'HTTP_USER_AGENT': USER_AGENT},
)
account_confirmation_email_mock.send.assert_called_once_with(
{
'language': 'en',
'email': email,
},
{
'username': username,
'fittrackee_url': 'http://0.0.0.0:5000',
'operating_system': 'linux',
'browser_name': 'firefox',
'account_confirmation_url': (
'http://0.0.0.0:5000/account-confirmation'
f'?token={expected_token}'
),
},
)
@pytest.mark.parametrize(
'text_transformation',
['upper', 'lower'],
)
def test_it_returns_error_if_user_already_exists_with_same_email(
def test_it_does_not_return_error_if_a_user_already_exists_with_same_email(
self, app: Flask, user_1: User, text_transformation: str
) -> None:
client = app.test_client()
@@ -217,29 +317,30 @@ class TestUserRegistration(ApiTestCaseMixin):
content_type='application/json',
)
self.assert_400(response, 'sorry, that user already exists')
assert response.status_code == 200
assert response.content_type == 'application/json'
data = json.loads(response.data.decode())
assert data['status'] == 'success'
assert 'auth_token' not in data
def test_user_can_register(self, app: Flask) -> None:
def test_it_does_not_call_account_confirmation_email_if_user_already_exists( # noqa
self, app: Flask, user_1: User, account_confirmation_email_mock: Mock
) -> None:
client = app.test_client()
response = client.post(
client.post(
'/api/auth/register',
data=json.dumps(
dict(
username=self.random_string(),
email=self.random_email(),
email=user_1.email,
password=self.random_string(),
)
),
content_type='application/json',
)
assert response.status_code == 201
assert response.content_type == 'application/json'
data = json.loads(response.data.decode())
assert data['status'] == 'success'
assert data['message'] == 'successfully registered'
assert data['auth_token']
account_confirmation_email_mock.send.assert_not_called()
class TestUserLogin(ApiTestCaseMixin):
@@ -269,6 +370,21 @@ class TestUserLogin(ApiTestCaseMixin):
self.assert_401(response, 'invalid credentials')
def test_it_returns_error_if_user_account_is_inactive(
self, app: Flask, inactive_user: User
) -> None:
client = app.test_client()
response = client.post(
'/api/auth/login',
data=json.dumps(
dict(email=inactive_user.email, password='12345678')
),
content_type='application/json',
)
self.assert_401(response, 'invalid credentials')
def test_it_returns_error_if_password_is_invalid(
self, app: Flask, user_1: User
) -> None:
@@ -1628,7 +1744,7 @@ class TestRegistrationConfiguration(ApiTestCaseMixin):
content_type='application/json',
)
assert response.status_code == 201
assert response.status_code == 200
class TestPasswordResetRequest(ApiTestCaseMixin):
@@ -1974,3 +2090,47 @@ class TestEmailUpdateWitUnauthenticatedUser(ApiTestCaseMixin):
assert user_1.email == new_email
assert user_1.email_to_confirm is None
assert user_1.confirmation_token is None
class TestConfirmationAccount(ApiTestCaseMixin):
def test_it_returns_error_if_token_is_missing(self, app: Flask) -> None:
client = app.test_client()
response = client.post(
'/api/auth/account/confirm',
data=json.dumps(dict()),
content_type='application/json',
)
self.assert_400(response)
def test_it_returns_error_if_token_is_invalid(self, app: Flask) -> None:
client = app.test_client()
response = client.post(
'/api/auth/account/confirm',
data=json.dumps(dict(token=self.random_string())),
content_type='application/json',
)
self.assert_400(response)
def test_it_activates_user_account(
self, app: Flask, inactive_user: User
) -> None:
token = self.random_string()
inactive_user.confirmation_token = token
client = app.test_client()
response = client.post(
'/api/auth/account/confirm',
data=json.dumps(dict(token=token)),
content_type='application/json',
)
assert response.status_code == 200
data = json.loads(response.data.decode())
assert data['status'] == 'success'
assert data['message'] == 'account confirmation successful'
assert inactive_user.is_active is True
assert inactive_user.confirmation_token is None

View File

@@ -28,6 +28,41 @@ class TestGetUser(ApiTestCaseMixin):
self.assert_403(response)
def test_it_gets_inactive_user(
self, app: Flask, user_1_admin: User, inactive_user: User
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app, user_1_admin.email
)
response = client.get(
f'/api/users/{inactive_user.username}',
content_type='application/json',
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert data['status'] == 'success'
assert len(data['data']['users']) == 1
user = data['data']['users'][0]
assert user['username'] == inactive_user.username
assert user['email'] == inactive_user.email
assert user['created_at']
assert not user['admin']
assert not user['is_active']
assert user['first_name'] is None
assert user['last_name'] is None
assert user['birth_date'] is None
assert user['bio'] is None
assert user['location'] is None
assert user['nb_sports'] == 0
assert user['nb_workouts'] == 0
assert user['records'] == []
assert user['sports_list'] == []
assert user['total_distance'] == 0
assert user['total_duration'] == '0:00:00'
def test_it_gets_single_user_without_workouts(
self, app: Flask, user_1_admin: User, user_2: User
) -> None:
@@ -46,10 +81,11 @@ class TestGetUser(ApiTestCaseMixin):
assert data['status'] == 'success'
assert len(data['data']['users']) == 1
user = data['data']['users'][0]
assert user['username'] == 'toto'
assert user['email'] == 'toto@toto.com'
assert user['username'] == user_2.username
assert user['email'] == user_2.email
assert user['created_at']
assert not user['admin']
assert user['is_active']
assert user['first_name'] is None
assert user['last_name'] is None
assert user['birth_date'] is None
@@ -87,10 +123,11 @@ class TestGetUser(ApiTestCaseMixin):
assert data['status'] == 'success'
assert len(data['data']['users']) == 1
user = data['data']['users'][0]
assert user['username'] == 'test'
assert user['email'] == 'test@test.com'
assert user['username'] == user_1.username
assert user['email'] == user_1.email
assert user['created_at']
assert not user['admin']
assert user['is_active']
assert user['first_name'] is None
assert user['last_name'] is None
assert user['birth_date'] is None
@@ -134,8 +171,8 @@ class TestGetUsers(ApiTestCaseMixin):
self.assert_403(response)
def test_it_get_users_list(
self, app: Flask, user_1_admin: User, user_2: User, user_3: User
def test_it_get_users_list_regardless_their_account_status(
self, app: Flask, user_1_admin: User, inactive_user: User, user_3: User
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app, user_1_admin.email
@@ -154,11 +191,14 @@ class TestGetUsers(ApiTestCaseMixin):
assert 'created_at' in data['data']['users'][1]
assert 'created_at' in data['data']['users'][2]
assert 'admin' in data['data']['users'][0]['username']
assert 'toto' in data['data']['users'][1]['username']
assert 'inactive' in data['data']['users'][1]['username']
assert 'sam' in data['data']['users'][2]['username']
assert 'admin@example.com' in data['data']['users'][0]['email']
assert 'toto@toto.com' in data['data']['users'][1]['email']
assert 'inactive@example.com' in data['data']['users'][1]['email']
assert 'sam@test.com' in data['data']['users'][2]['email']
assert data['data']['users'][0]['is_active']
assert not data['data']['users'][1]['is_active']
assert data['data']['users'][2]['is_active']
assert data['data']['users'][0]['imperial_units'] is False
assert data['data']['users'][0]['timezone'] is None
assert data['data']['users'][0]['weekm'] is False
@@ -223,6 +263,9 @@ class TestGetUsers(ApiTestCaseMixin):
assert 'admin@example.com' in data['data']['users'][0]['email']
assert 'toto@toto.com' in data['data']['users'][1]['email']
assert 'sam@test.com' in data['data']['users'][2]['email']
assert data['data']['users'][0]['is_active']
assert data['data']['users'][1]['is_active']
assert data['data']['users'][2]['is_active']
assert data['data']['users'][0]['imperial_units'] is False
assert data['data']['users'][0]['timezone'] is None
assert data['data']['users'][0]['weekm'] is False
@@ -1344,7 +1387,7 @@ class TestDeleteUser(ApiTestCaseMixin):
'you can not delete your account, no other user has admin rights',
)
def test_it_enables_registration_on_user_delete(
def test_it_enables_registration_after_user_delete(
self,
app_with_3_users_max: Flask,
user_1_admin: User,
@@ -1363,15 +1406,15 @@ class TestDeleteUser(ApiTestCaseMixin):
'/api/auth/register',
data=json.dumps(
dict(
username='justatest',
email='test@test.com',
password='12345678',
password_conf='12345678',
username=self.random_string(),
email=self.random_email(),
password=self.random_string(),
)
),
content_type='application/json',
)
assert response.status_code == 201
assert response.status_code == 200
def test_it_does_not_enable_registration_on_user_delete(
self,

View File

@@ -14,6 +14,7 @@ class TestUserModel:
assert 'created_at' in serialized_user
assert serialized_user['admin'] is False
assert serialized_user['first_name'] is None
assert serialized_user['is_active']
assert serialized_user['last_name'] is None
assert serialized_user['bio'] is None
assert serialized_user['location'] is None
@@ -99,6 +100,15 @@ class TestUserModel:
)
assert serialized_user['records'][0]['workout_date']
def test_it_returns_is_active_to_false_fot_inactive_user(
self,
app: Flask,
inactive_user: User,
) -> None:
serialized_user = inactive_user.serialize(inactive_user)
assert serialized_user['is_active'] is False
class TestUserSportModel:
def test_user_model(

View File

@@ -887,3 +887,13 @@ class TestGetRecords(ApiTestCaseMixin):
assert workout_4_short_id == data['data']['records'][7]['workout_id']
assert 'MS' == data['data']['records'][7]['record_type']
assert 12.0 == data['data']['records'][7]['value']
def test_it_returns_error_if_user_is_not_authenticated(
self,
app: Flask,
) -> None:
client = app.test_client()
response = client.get('/api/records')
self.assert_401(response)

View File

@@ -45,6 +45,16 @@ expected_sport_1_cycling_inactive_admin_result['has_workouts'] = False
class TestGetSports(ApiTestCaseMixin):
def test_it_returns_error_if_user_is_not_authenticated(
self,
app: Flask,
) -> None:
client = app.test_client()
response = client.get('/api/sports')
self.assert_401(response)
def test_it_gets_all_sports(
self,
app: Flask,

View File

@@ -9,6 +9,17 @@ from ..mixins import ApiTestCaseMixin
class TestGetStatsByTime(ApiTestCaseMixin):
def test_it_returns_error_if_user_is_not_authenticated(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
response = client.get(
f'/api/stats/{user_1.username}/by_time',
)
self.assert_401(response)
def test_it_gets_no_stats_when_user_has_no_workouts(
self, app: Flask, user_1: User
) -> None:
@@ -853,6 +864,17 @@ class TestGetStatsByTime(ApiTestCaseMixin):
class TestGetStatsBySport(ApiTestCaseMixin):
def test_it_returns_error_if_user_is_not_authenticated(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
response = client.get(
f'/api/stats/{user_1.username}/by_sport',
)
self.assert_401(response)
def test_it_gets_stats_by_sport(
self,
app: Flask,
@@ -987,6 +1009,15 @@ class TestGetStatsBySport(ApiTestCaseMixin):
class TestGetAllStats(ApiTestCaseMixin):
def test_it_returns_error_if_user_is_not_authenticated(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
response = client.get('/api/stats/all')
self.assert_401(response)
def test_it_returns_all_stats_when_users_have_no_workouts(
self, app: Flask, user_1_admin: User, user_2: User
) -> None:

View File

@@ -12,6 +12,15 @@ from .utils import get_random_short_id
class TestGetWorkouts(ApiTestCaseMixin):
def test_it_returns_error_if_user_is_not_authenticated(
self, app: Flask
) -> None:
client = app.test_client()
response = client.get('/api/workouts')
self.assert_401(response)
def test_it_gets_all_workouts_for_authenticated_user(
self,
app: Flask,

View File

@@ -206,6 +206,22 @@ def assert_workout_data_wo_gpx(data: Dict) -> None:
class TestPostWorkoutWithGpx(ApiTestCaseMixin, CallArgsMixin):
def test_it_returns_error_if_user_is_not_authenticated(
self, app: Flask, sport_1_cycling: Sport, gpx_file: str
) -> None:
client = app.test_client()
response = client.post(
'/api/workouts',
data=dict(
file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
data='{"sport_id": 1}',
),
headers=dict(content_type='multipart/form-data'),
)
self.assert_401(response)
def test_it_adds_an_workout_with_gpx_file(
self, app: Flask, user_1: User, sport_1_cycling: Sport, gpx_file: str
) -> None:
@@ -569,6 +585,27 @@ class TestPostWorkoutWithGpx(ApiTestCaseMixin, CallArgsMixin):
class TestPostWorkoutWithoutGpx(ApiTestCaseMixin):
def test_it_returns_error_if_user_is_not_authenticated(
self, app: Flask, sport_1_cycling: Sport, gpx_file: str
) -> None:
client = app.test_client()
response = client.post(
'/api/workouts/no_gpx',
content_type='application/json',
data=json.dumps(
dict(
sport_id=1,
duration=3600,
workout_date='2018-05-15 14:05',
distance=10,
)
),
headers=dict(content_type='multipart/form-data'),
)
self.assert_401(response)
def test_it_adds_an_workout_without_gpx(
self, app: Flask, user_1: User, sport_1_cycling: Sport
) -> None: