FitTrackee/fittrackee/tests/application/test_app_config_api.py

460 lines
15 KiB
Python
Raw Normal View History

import json
2023-02-25 14:06:49 +01:00
from datetime import datetime
from typing import Optional
2023-02-25 14:06:49 +01:00
from unittest.mock import Mock, patch
import pytest
2021-01-02 19:28:03 +01:00
from flask import Flask
from fittrackee import db
from fittrackee.application.models import AppConfig
2021-01-20 16:47:00 +01:00
from fittrackee.users.models import User
from ..mixins import ApiTestCaseMixin
2023-05-21 16:13:14 +02:00
from ..utils import OAUTH_SCOPES, jsonify_dict
2021-02-20 23:20:20 +01:00
class TestGetConfig(ApiTestCaseMixin):
2022-03-19 22:02:06 +01:00
def test_it_gets_application_config_for_unauthenticated_user(
self, app: Flask
2021-01-02 19:28:03 +01:00
) -> None:
app_config = AppConfig.query.first()
2022-03-19 22:02:06 +01:00
client = app.test_client()
2020-05-10 15:55:56 +02:00
2022-03-19 22:02:06 +01:00
response = client.get('/api/config')
2020-05-10 15:55:56 +02:00
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert data['data'] == jsonify_dict(app_config.serialize())
2020-05-10 15:55:56 +02:00
2022-03-19 22:02:06 +01:00
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']
2020-05-10 15:55:56 +02:00
def test_it_returns_error_if_application_has_no_config(
2021-01-02 19:28:03 +01:00
self, app_no_config: Flask, user_1_admin: User
) -> None:
2021-02-20 23:20:20 +01:00
client, auth_token = self.get_test_client_and_auth_token(
app_no_config, user_1_admin.email
2020-05-10 15:55:56 +02:00
)
response = client.get(
'/api/config',
content_type='application/json',
2021-02-20 23:20:20 +01:00
headers=dict(Authorization=f'Bearer {auth_token}'),
2020-05-10 15:55:56 +02:00
)
self.assert_500(response, 'error on getting configuration')
2020-05-10 15:55:56 +02:00
def test_it_returns_error_if_application_has_several_config(
2021-01-02 19:28:03 +01:00
self, app: Flask, app_config: Flask, user_1_admin: User
) -> None:
2021-02-20 23:20:20 +01:00
client, auth_token = self.get_test_client_and_auth_token(
app, user_1_admin.email
2020-05-10 15:55:56 +02:00
)
response = client.get(
'/api/config',
content_type='application/json',
2021-02-20 23:20:20 +01:00
headers=dict(Authorization=f'Bearer {auth_token}'),
2020-05-10 15:55:56 +02:00
)
self.assert_500(response, 'error on getting configuration')
2020-05-10 15:55:56 +02:00
2021-02-20 23:20:20 +01:00
class TestUpdateConfig(ApiTestCaseMixin):
2021-01-02 19:28:03 +01:00
def test_it_updates_config_when_user_is_admin(
self, app: Flask, user_1_admin: User
) -> None:
2021-02-20 23:20:20 +01:00
client, auth_token = self.get_test_client_and_auth_token(
app, user_1_admin.email
2020-05-10 15:55:56 +02:00
)
response = client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(dict(gpx_limit_import=100, max_users=10)),
2021-02-20 23:20:20 +01:00
headers=dict(Authorization=f'Bearer {auth_token}'),
2020-05-10 15:55:56 +02:00
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert data['data']['gpx_limit_import'] == 100
assert data['data']['is_registration_enabled'] is True
assert data['data']['max_single_file_size'] == 1048576
assert data['data']['max_zip_file_size'] == 10485760
assert data['data']['max_users'] == 10
2021-01-02 19:28:03 +01:00
def test_it_updates_all_config(
self, app: Flask, user_1_admin: User
) -> None:
2021-02-20 23:20:20 +01:00
client, auth_token = self.get_test_client_and_auth_token(
app, user_1_admin.email
2020-05-10 15:55:56 +02:00
)
admin_email = self.random_email()
2020-05-10 15:55:56 +02:00
response = client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(
dict(
admin_contact=admin_email,
2020-05-10 15:55:56 +02:00
gpx_limit_import=20,
max_single_file_size=10000,
max_zip_file_size=25000,
max_users=50,
)
),
2021-02-20 23:20:20 +01:00
headers=dict(Authorization=f'Bearer {auth_token}'),
2020-05-10 15:55:56 +02:00
)
assert response.status_code == 200
data = json.loads(response.data.decode())
2020-05-10 15:55:56 +02:00
assert 'success' in data['status']
assert data['data']['admin_contact'] == admin_email
2020-05-10 15:55:56 +02:00
assert data['data']['gpx_limit_import'] == 20
assert data['data']['is_registration_enabled'] is True
assert data['data']['max_single_file_size'] == 10000
assert data['data']['max_zip_file_size'] == 25000
assert data['data']['max_users'] == 50
2021-01-02 19:28:03 +01:00
def test_it_returns_403_when_user_is_not_an_admin(
self, app: Flask, user_1: User
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email
)
2020-05-10 15:55:56 +02:00
response = client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(dict(gpx_limit_import=100, max_users=10)),
2021-02-20 23:20:20 +01:00
headers=dict(Authorization=f'Bearer {auth_token}'),
2020-05-10 15:55:56 +02:00
)
self.assert_403(response)
2020-05-10 15:55:56 +02:00
2021-01-02 19:28:03 +01:00
def test_it_returns_400_if_invalid_is_payload(
self, app: Flask, user_1_admin: User
) -> None:
2021-02-20 23:20:20 +01:00
client, auth_token = self.get_test_client_and_auth_token(
app, user_1_admin.email
2020-05-10 15:55:56 +02:00
)
response = client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(dict()),
2021-02-20 23:20:20 +01:00
headers=dict(Authorization=f'Bearer {auth_token}'),
2020-05-10 15:55:56 +02:00
)
self.assert_400(response)
2020-05-10 15:55:56 +02:00
def test_it_returns_error_on_update_if_application_has_no_config(
2021-01-02 19:28:03 +01:00
self, app_no_config: Flask, user_1_admin: User
) -> None:
2021-02-20 23:20:20 +01:00
client, auth_token = self.get_test_client_and_auth_token(
app_no_config, user_1_admin.email
2020-05-10 15:55:56 +02:00
)
response = client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(dict(gpx_limit_import=100, max_users=10)),
2021-02-20 23:20:20 +01:00
headers=dict(Authorization=f'Bearer {auth_token}'),
2020-05-10 15:55:56 +02:00
)
self.assert_500(response, 'error when updating configuration')
def test_it_raises_error_if_archive_max_size_is_below_files_max_size(
self, app: Flask, user_1_admin: User
) -> None:
2021-02-20 23:20:20 +01:00
client, auth_token = self.get_test_client_and_auth_token(
app, user_1_admin.email
)
response = client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(
dict(
gpx_limit_import=20,
max_single_file_size=10000,
max_zip_file_size=1000,
max_users=50,
)
),
2021-02-20 23:20:20 +01:00
headers=dict(Authorization=f'Bearer {auth_token}'),
)
self.assert_400(
response,
(
'Max. size of zip archive must be equal or greater than max.'
' size of uploaded files'
),
)
def test_it_raises_error_if_archive_max_size_equals_0(
self, app_with_max_file_size_equals_0: Flask, user_1_admin: User
) -> None:
2021-02-20 23:20:20 +01:00
client, auth_token = self.get_test_client_and_auth_token(
app_with_max_file_size_equals_0, user_1_admin.email
)
response = client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(
dict(
max_zip_file_size=0,
)
),
2021-02-20 23:20:20 +01:00
headers=dict(Authorization=f'Bearer {auth_token}'),
)
self.assert_400(
response, 'Max. size of zip archive must be greater than 0'
)
def test_it_raises_error_if_files_max_size_equals_0(
self, app: Flask, user_1_admin: User
) -> None:
2021-02-20 23:20:20 +01:00
client, auth_token = self.get_test_client_and_auth_token(
app, user_1_admin.email
)
response = client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(
dict(
max_single_file_size=0,
)
),
2021-02-20 23:20:20 +01:00
headers=dict(Authorization=f'Bearer {auth_token}'),
)
self.assert_400(
response, 'Max. size of uploaded files must be greater than 0'
)
def test_it_raises_error_if_gpx_limit_import_equals_0(
self, app: Flask, user_1_admin: User
) -> None:
2021-02-20 23:20:20 +01:00
client, auth_token = self.get_test_client_and_auth_token(
app, user_1_admin.email
)
response = client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(
dict(
gpx_limit_import=0,
)
),
2021-02-20 23:20:20 +01:00
headers=dict(Authorization=f'Bearer {auth_token}'),
)
self.assert_400(
response, 'Max. files in a zip archive must be greater than 0'
)
def test_it_raises_error_if_admin_contact_is_invalid(
self, app: Flask, user_1_admin: User
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app, user_1_admin.email
)
response = client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(
dict(
admin_contact=self.random_string(),
)
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
self.assert_400(
response, 'valid email must be provided for admin contact'
)
@pytest.mark.parametrize(
'input_description,input_email', [('input string', ''), ('None', None)]
)
2023-03-04 18:03:52 +01:00
def test_it_empties_administator_contact(
self,
app: Flask,
user_1_admin: User,
input_description: str,
input_email: Optional[str],
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app, user_1_admin.email
)
app_config = AppConfig.query.first()
app_config.admin_contact = self.random_email()
response = client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(
dict(
admin_contact=input_email,
)
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
assert response.status_code == 200
data = json.loads(response.data.decode())
assert 'success' in data['status']
assert data['data']['admin_contact'] is None
2022-06-15 19:16:14 +02:00
2023-02-25 14:06:49 +01:00
def test_it_updates_about(
self,
app: Flask,
user_1_admin: User,
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app, user_1_admin.email
)
about = self.random_string()
response = client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(dict(about=about)),
2023-02-25 14:06:49 +01:00
headers=dict(Authorization=f'Bearer {auth_token}'),
)
assert response.status_code == 200
data = json.loads(response.data.decode())
assert 'success' in data['status']
assert data['data']['about'] == about
def test_it_empties_about_text_when_text_is_an_empty_string(
self, app: Flask, user_1_admin: User
) -> None:
app_config = AppConfig.query.first()
app_config.about = self.random_string()
db.session.commit()
client, auth_token = self.get_test_client_and_auth_token(
app, user_1_admin.email
)
response = client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(dict(about='')),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
assert response.status_code == 200
data = json.loads(response.data.decode())
assert 'success' in data['status']
assert data['data']['about'] is None
2023-02-25 14:06:49 +01:00
def test_it_updates_privacy_policy(
self,
app: Flask,
user_1_admin: User,
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app, user_1_admin.email
)
privacy_policy = self.random_string()
privacy_policy_date = datetime.utcnow()
with patch(
'fittrackee.application.app_config.datetime'
) as datetime_mock:
datetime_mock.utcnow = Mock(return_value=privacy_policy_date)
response = client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(dict(privacy_policy=privacy_policy)),
2023-02-25 14:06:49 +01:00
headers=dict(Authorization=f'Bearer {auth_token}'),
)
assert response.status_code == 200
data = json.loads(response.data.decode())
assert 'success' in data['status']
assert data['data']['privacy_policy'] == privacy_policy
assert data['data'][
'privacy_policy_date'
] == privacy_policy_date.strftime('%a, %d %b %Y %H:%M:%S GMT')
@pytest.mark.parametrize('input_privacy_policy', ['', None])
def test_it_empties_privacy_policy_date_when_no_privacy_policy(
self,
app: Flask,
user_1_admin: User,
input_privacy_policy: Optional[str],
) -> None:
app_config = AppConfig.query.first()
app_config.privacy_policy = self.random_string()
app_config.privacy_policy_date = datetime.utcnow()
db.session.commit()
client, auth_token = self.get_test_client_and_auth_token(
app, user_1_admin.email
)
response = client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(dict(privacy_policy=input_privacy_policy)),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
assert response.status_code == 200
data = json.loads(response.data.decode())
assert 'success' in data['status']
assert data['data']['privacy_policy'] is None
assert data['data']['privacy_policy_date'] is None
2022-06-15 19:16:14 +02:00
@pytest.mark.parametrize(
'client_scope, can_access',
2023-05-21 16:13:14 +02:00
{**OAUTH_SCOPES, 'application:write': True}.items(),
2022-06-15 19:16:14 +02:00
)
def test_expected_scopes_are_defined(
self,
app: Flask,
user_1_admin: User,
client_scope: str,
can_access: bool,
) -> None:
(
client,
oauth_client,
access_token,
_,
2022-06-19 20:04:42 +02:00
) = self.create_oauth2_client_and_issue_token(
2022-06-15 19:16:14 +02:00
app, user_1_admin, scope=client_scope
)
response = client.patch(
'/api/config',
content_type='application/json',
headers=dict(Authorization=f'Bearer {access_token}'),
)
self.assert_response_scope(response, can_access)