import json from typing import Optional import pytest from flask import Flask from fittrackee.application.models import AppConfig from fittrackee.users.models import User from ..mixins import ApiTestCaseMixin from ..utils import jsonify_dict class TestGetConfig(ApiTestCaseMixin): def test_it_gets_application_config_for_unauthenticated_user( self, app: Flask ) -> None: app_config = AppConfig.query.first() client = app.test_client() response = client.get('/api/config') data = json.loads(response.data.decode()) assert response.status_code == 200 assert 'success' in data['status'] assert data['data'] == jsonify_dict(app_config.serialize()) 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: client, auth_token = self.get_test_client_and_auth_token( app_no_config, user_1_admin.email ) response = client.get( '/api/config', content_type='application/json', headers=dict(Authorization=f'Bearer {auth_token}'), ) self.assert_500(response, 'error on getting configuration') def test_it_returns_error_if_application_has_several_config( self, app: Flask, app_config: Flask, user_1_admin: User ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1_admin.email ) response = client.get( '/api/config', content_type='application/json', headers=dict(Authorization=f'Bearer {auth_token}'), ) self.assert_500(response, 'error on getting configuration') class TestUpdateConfig(ApiTestCaseMixin): def test_it_updates_config_when_user_is_admin( 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(gpx_limit_import=100, max_users=10)), headers=dict(Authorization=f'Bearer {auth_token}'), ) 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 def test_it_updates_all_config( self, app: Flask, user_1_admin: User ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1_admin.email ) admin_email = self.random_email() response = client.patch( '/api/config', content_type='application/json', data=json.dumps( dict( admin_contact=admin_email, gpx_limit_import=20, max_single_file_size=10000, max_zip_file_size=25000, max_users=50, ) ), 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'] == admin_email 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 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 ) response = client.patch( '/api/config', content_type='application/json', data=json.dumps(dict(gpx_limit_import=100, max_users=10)), headers=dict(Authorization=f'Bearer {auth_token}'), ) self.assert_403(response) def test_it_returns_400_if_invalid_is_payload( 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()), headers=dict(Authorization=f'Bearer {auth_token}'), ) self.assert_400(response) def test_it_returns_error_on_update_if_application_has_no_config( self, app_no_config: Flask, user_1_admin: User ) -> None: client, auth_token = self.get_test_client_and_auth_token( app_no_config, user_1_admin.email ) response = client.patch( '/api/config', content_type='application/json', data=json.dumps(dict(gpx_limit_import=100, max_users=10)), headers=dict(Authorization=f'Bearer {auth_token}'), ) 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: 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, ) ), 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: 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, ) ), 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: 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, ) ), 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: 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, ) ), 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)] ) def test_it_empties_error_if_admin_contact_is_an_empty( 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 @pytest.mark.parametrize( 'client_scope, can_access', [ ('application:write', True), ('profile:read', False), ('profile:write', False), ('users:read', False), ('users:write', False), ('workouts:read', False), ('workouts:write', False), ], ) 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, _, ) = self.create_oauth2_client_and_issue_token( 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)