Merge pull request #73 from SamR1/fix-app-config-update

Fix files upload configuration
This commit is contained in:
Sam 2021-02-21 20:03:23 +01:00 committed by GitHub
commit e205ac3eda
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 1175 additions and 2188 deletions

View File

@ -12,10 +12,14 @@ Administration
The following parameters can be set:
- active users limit (if 0, registration is enabled (no limit defined))
- active users limit. If 0, registration is enabled (no limit defined)
- maximum size of uploaded files
- maximum size of zip archive
- maximum number of files in the zip archive
- maximum number of files in the zip archive. If an archive contains more files, only the configured number of files is processed, without raising errors.
.. warning::
Updating server configuration may be necessary to handle large files (like `nginx <https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size>`_ for instance).
- **Users**

View File

@ -571,6 +571,9 @@ Examples (to update depending on your application configuration and given distri
[Install]
WantedBy=multi-user.target
.. note::
More information on `Gunicorn documentation <https://docs.gunicorn.org/en/stable/deploy.html>`__
- for task queue workers: ``fittrackee_workers.service``
.. code-block::
@ -635,7 +638,7 @@ Examples (to update depending on your application configuration and given distri
}
.. note::
More information on `Gunicorn documentation <https://docs.gunicorn.org/en/stable/deploy.html>`__
If needed, update configuration to handle larger files (see `client_max_body_size <https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size>`_).
Docker

View File

@ -196,11 +196,11 @@
</dd>
<dt class="field-even">Request JSON Object</dt>
<dd class="field-even"><ul class="simple">
<li><p><strong>gpx_limit_import</strong> (<em>integrer</em>) max number of files in zip archive</p></li>
<li><p><strong>gpx_limit_import</strong> (<em>integer</em>) max number of files in zip archive</p></li>
<li><p><strong>is_registration_enabled</strong> (<em>boolean</em>) is registration enabled ?</p></li>
<li><p><strong>max_single_file_size</strong> (<em>integrer</em>) max size of a single file</p></li>
<li><p><strong>max_zip_file_size</strong> (<em>integrer</em>) max size of a zip archive</p></li>
<li><p><strong>max_users</strong> (<em>integrer</em>) max users allowed to register on instance</p></li>
<li><p><strong>max_single_file_size</strong> (<em>integer</em>) max size of a single file</p></li>
<li><p><strong>max_zip_file_size</strong> (<em>integer</em>) max size of a zip archive</p></li>
<li><p><strong>max_users</strong> (<em>integer</em>) max users allowed to register on instance</p></li>
</ul>
</dd>
<dt class="field-odd">Request Headers</dt>

View File

@ -149,11 +149,15 @@
<li><p><strong>Application</strong></p>
<p>The following parameters can be set:</p>
<ul class="simple">
<li><p>active users limit (if 0, registration is enabled (no limit defined))</p></li>
<li><p>active users limit. If 0, registration is enabled (no limit defined)</p></li>
<li><p>maximum size of uploaded files</p></li>
<li><p>maximum size of zip archive</p></li>
<li><p>maximum number of files in the zip archive</p></li>
<li><p>maximum number of files in the zip archive. If an archive contains more files, only the configured number of files is processed, without raising errors.</p></li>
</ul>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Updating server configuration may be necessary to handle large files (like <a class="reference external" href="https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size">nginx</a> for instance).</p>
</div>
</li>
<li><p><strong>Users</strong></p>
<ul class="simple">

View File

@ -832,6 +832,10 @@ One way is to use a <strong>systemd</strong> services and <strong>Nginx</strong>
<span class="n">WantedBy</span><span class="o">=</span><span class="n">multi</span><span class="o">-</span><span class="n">user</span><span class="o">.</span><span class="n">target</span>
</pre></div>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>More information on <a class="reference external" href="https://docs.gunicorn.org/en/stable/deploy.html">Gunicorn documentation</a></p>
</div>
<ul class="simple">
<li><p>for task queue workers: <code class="docutils literal notranslate"><span class="pre">fittrackee_workers.service</span></code></p></li>
</ul>
@ -897,7 +901,7 @@ server {
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>More information on <a class="reference external" href="https://docs.gunicorn.org/en/stable/deploy.html">Gunicorn documentation</a></p>
<p>If needed, update configuration to handle larger files (see <a class="reference external" href="https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size">client_max_body_size</a>).</p>
</div>
</div>
<div class="section" id="docker">

File diff suppressed because one or more lines are too long

View File

@ -12,10 +12,14 @@ Administration
The following parameters can be set:
- active users limit (if 0, registration is enabled (no limit defined))
- active users limit. If 0, registration is enabled (no limit defined)
- maximum size of uploaded files
- maximum size of zip archive
- maximum number of files in the zip archive
- maximum number of files in the zip archive. If an archive contains more files, only the configured number of files is processed, without raising errors.
.. warning::
Updating server configuration may be necessary to handle large files (like `nginx <https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size>`_ for instance).
- **Users**

View File

@ -571,6 +571,9 @@ Examples (to update depending on your application configuration and given distri
[Install]
WantedBy=multi-user.target
.. note::
More information on `Gunicorn documentation <https://docs.gunicorn.org/en/stable/deploy.html>`__
- for task queue workers: ``fittrackee_workers.service``
.. code-block::
@ -635,7 +638,7 @@ Examples (to update depending on your application configuration and given distri
}
.. note::
More information on `Gunicorn documentation <https://docs.gunicorn.org/en/stable/deploy.html>`__
If needed, update configuration to handle larger files (see `client_max_body_size <https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size>`_).
Docker

View File

@ -12,7 +12,7 @@ from fittrackee.responses import (
from fittrackee.users.decorators import authenticate_as_admin
from .models import AppConfig
from .utils import update_app_config_from_database
from .utils import update_app_config_from_database, verify_app_config
config_blueprint = Blueprint('config', __name__)
@ -96,11 +96,11 @@ def update_application_config(auth_user_id: int) -> Union[Dict, HttpResponse]:
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:<json integrer gpx_limit_import: max number of files in zip archive
:<json integer gpx_limit_import: max number of files in zip archive
:<json boolean is_registration_enabled: is registration enabled ?
:<json integrer max_single_file_size: max size of a single file
:<json integrer max_zip_file_size: max size of a zip archive
:<json integrer max_users: max users allowed to register on instance
:<json integer max_single_file_size: max size of a single file
:<json integer max_zip_file_size: max size of a zip archive
:<json integer max_users: max users allowed to register on instance
:reqheader Authorization: OAuth 2.0 Bearer Token
@ -117,6 +117,10 @@ def update_application_config(auth_user_id: int) -> Union[Dict, HttpResponse]:
if not config_data:
return InvalidPayloadErrorResponse()
ret = verify_app_config(config_data)
if ret:
return InvalidPayloadErrorResponse(message=ret)
try:
config = AppConfig.query.one()
if 'gpx_limit_import' in config_data:
@ -130,6 +134,11 @@ def update_application_config(auth_user_id: int) -> Union[Dict, HttpResponse]:
if 'max_users' in config_data:
config.max_users = config_data.get('max_users')
if config.max_zip_file_size < config.max_single_file_size:
return InvalidPayloadErrorResponse(
'Max. size of zip archive must be equal or greater than '
'max. size of uploaded files'
)
db.session.commit()
update_app_config_from_database(current_app, config)
return {'status': 'success', 'data': config.serialize()}

View File

@ -1,5 +1,5 @@
import os
from typing import Tuple
from typing import Dict, List, Tuple
from flask import Flask
@ -49,3 +49,30 @@ def update_app_config_from_database(
current_app.config[
'is_registration_enabled'
] = db_config.is_registration_enabled
def verify_app_config(config_data: Dict) -> List:
"""
Verify if application config is valid.
If not, it returns not empty string
"""
ret = []
if (
'gpx_limit_import' in config_data
and config_data['gpx_limit_import'] <= 0
):
ret.append('Max. files in a zip archive must be greater than 0')
if (
'max_single_file_size' in config_data
and config_data['max_single_file_size'] <= 0
):
ret.append('Max. size of uploaded files must be greater than 0')
if (
'max_zip_file_size' in config_data
and config_data['max_zip_file_size'] <= 0
):
ret.append('Max. size of zip archive must be greater than 0')
return ret

View File

@ -1,14 +1,14 @@
{
"files": {
"main.css": "/static/css/main.376b8924.chunk.css",
"main.js": "/static/js/main.8faa878d.chunk.js",
"main.js.map": "/static/js/main.8faa878d.chunk.js.map",
"main.css": "/static/css/main.47c735b4.chunk.css",
"main.js": "/static/js/main.75f806db.chunk.js",
"main.js.map": "/static/js/main.75f806db.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.1240af94.js",
"runtime-main.js.map": "/static/js/runtime-main.1240af94.js.map",
"static/js/2.301144a0.chunk.js": "/static/js/2.301144a0.chunk.js",
"static/js/2.301144a0.chunk.js.map": "/static/js/2.301144a0.chunk.js.map",
"index.html": "/index.html",
"static/css/main.376b8924.chunk.css.map": "/static/css/main.376b8924.chunk.css.map",
"static/css/main.47c735b4.chunk.css.map": "/static/css/main.47c735b4.chunk.css.map",
"static/js/2.301144a0.chunk.js.LICENSE.txt": "/static/js/2.301144a0.chunk.js.LICENSE.txt",
"static/media/en.9e6dbfb0.svg": "/static/media/en.9e6dbfb0.svg",
"static/media/fr.d0f9280c.svg": "/static/media/fr.d0f9280c.svg",
@ -18,7 +18,7 @@
"entrypoints": [
"static/js/runtime-main.1240af94.js",
"static/js/2.301144a0.chunk.js",
"static/css/main.376b8924.chunk.css",
"static/js/main.8faa878d.chunk.js"
"static/css/main.47c735b4.chunk.css",
"static/js/main.75f806db.chunk.js"
]
}

View File

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="theme-color" content="#000000"><link rel="manifest" href="/manifest.json"><link rel="shortcut icon" href="/favicon.ico"><link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.1.7/css/fork-awesome.min.css" integrity="sha256-gsmEoJAws/Kd3CjuOQzLie5Q3yshhvmo7YNtBG7aaEY=" crossorigin="anonymous"><link rel="stylesheet" href="https://cdn.jsdelivr.net/foundation-icons/3.0/foundation-icons.min.css"><link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""><title>FitTrackee</title><link href="/static/css/main.376b8924.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script><script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script><script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script><script type="text/javascript">$(document).ready((function(){$("li.nav-item").click((function(){$("button.navbar-toggler").toggleClass("collapsed"),$("#navbarSupportedContent").toggleClass("show")}))}))</script><script>!function(e){function t(t){for(var n,i,l=t[0],f=t[1],a=t[2],p=0,s=[];p<l.length;p++)i=l[p],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(c&&c(t);s.length;)s.shift()();return u.push.apply(u,a||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,l=1;l<r.length;l++){var f=r[l];0!==o[f]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={1:0},u=[];function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/";var l=this.webpackJsonpfittrackee_client=this.webpackJsonpfittrackee_client||[],f=l.push.bind(l);l.push=t,l=l.slice();for(var a=0;a<l.length;a++)t(l[a]);var c=f;r()}([])</script><script src="/static/js/2.301144a0.chunk.js"></script><script src="/static/js/main.8faa878d.chunk.js"></script></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="theme-color" content="#000000"><link rel="manifest" href="/manifest.json"><link rel="shortcut icon" href="/favicon.ico"><link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.1.7/css/fork-awesome.min.css" integrity="sha256-gsmEoJAws/Kd3CjuOQzLie5Q3yshhvmo7YNtBG7aaEY=" crossorigin="anonymous"><link rel="stylesheet" href="https://cdn.jsdelivr.net/foundation-icons/3.0/foundation-icons.min.css"><link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""><title>FitTrackee</title><link href="/static/css/main.47c735b4.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script><script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script><script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script><script type="text/javascript">$(document).ready((function(){$("li.nav-item").click((function(){$("button.navbar-toggler").toggleClass("collapsed"),$("#navbarSupportedContent").toggleClass("show")}))}))</script><script>!function(e){function t(t){for(var n,i,l=t[0],f=t[1],a=t[2],p=0,s=[];p<l.length;p++)i=l[p],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(c&&c(t);s.length;)s.shift()();return u.push.apply(u,a||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,l=1;l<r.length;l++){var f=r[l];0!==o[f]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={1:0},u=[];function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/";var l=this.webpackJsonpfittrackee_client=this.webpackJsonpfittrackee_client||[],f=l.push.bind(l);l.push=t,l=l.slice();for(var a=0;a<l.length;a++)t(l[a]);var c=f;r()}([])</script><script src="/static/js/2.301144a0.chunk.js"></script><script src="/static/js/main.75f806db.chunk.js"></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -11,6 +11,21 @@ def get_empty_data_for_datatype(data_type: str) -> Union[str, List]:
return '' if data_type in ['gpx', 'chart_data'] else []
def display_readable_file_size(size_in_bytes: Union[float, int]) -> str:
"""
Return readable file size from size in bytes
"""
if size_in_bytes == 0:
return '0 bytes'
if size_in_bytes == 1:
return '1 byte'
for unit in [' bytes', 'KB', 'MB', 'GB', 'TB']:
if abs(size_in_bytes) < 1024.0:
return f'{size_in_bytes:3.1f}{unit}'
size_in_bytes /= 1024.0
return f'{size_in_bytes} bytes'
class HttpResponse(Response):
def __init__(
self,
@ -32,7 +47,10 @@ class HttpResponse(Response):
class GenericErrorResponse(HttpResponse):
def __init__(
self, status_code: int, message: str, status: Optional[str] = None
self,
status_code: int,
message: Union[str, List],
status: Optional[str] = None,
) -> None:
response = {
'status': 'error' if status is None else status,
@ -46,7 +64,9 @@ class GenericErrorResponse(HttpResponse):
class InvalidPayloadErrorResponse(GenericErrorResponse):
def __init__(
self, message: Optional[str] = None, status: Optional[str] = None
self,
message: Optional[Union[str, List]] = None,
status: Optional[str] = None,
) -> None:
message = 'Invalid payload.' if message is None else message
super().__init__(status_code=400, message=message, status=status)
@ -101,7 +121,19 @@ class DataNotFoundErrorResponse(HttpResponse):
class PayloadTooLargeErrorResponse(GenericErrorResponse):
def __init__(self, message: str) -> None:
def __init__(
self, file_type: str, file_size: Optional[int], max_size: Optional[int]
) -> None:
readable_file_size = (
f'({display_readable_file_size(file_size)}) ' if file_size else ''
)
readable_max_size = (
display_readable_file_size(max_size) if max_size else 'limit'
)
message = (
f'Error during {file_type} upload, file size {readable_file_size}'
f'exceeds {readable_max_size}.'
)
super().__init__(status_code=413, message=message, status='fail')

View File

@ -0,0 +1,25 @@
import json
from typing import Tuple
from flask import Flask
from flask.testing import FlaskClient
class ApiTestCaseMixin:
@staticmethod
def get_test_client_and_auth_token(
app: Flask, as_admin: bool = False
) -> Tuple[FlaskClient, str]:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(
email='admin@example.com' if as_admin else 'test@test.com',
password='12345678',
)
),
content_type='application/json',
)
auth_token = json.loads(resp_login.data.decode())['auth_token']
return client, auth_token

View File

@ -4,24 +4,18 @@ from flask import Flask
from fittrackee.users.models import User
from ..api_test_case import ApiTestCaseMixin
class TestGetConfig:
class TestGetConfig(ApiTestCaseMixin):
def test_it_gets_application_config(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/config',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -41,22 +35,14 @@ class TestGetConfig:
def test_it_returns_error_if_application_has_no_config(
self, app_no_config: Flask, user_1_admin: User
) -> None:
client = app_no_config.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app_no_config, as_admin=True
)
response = client.get(
'/api/config',
content_type='application/json',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -67,22 +53,14 @@ class TestGetConfig:
def test_it_returns_error_if_application_has_several_config(
self, app: Flask, app_config: Flask, user_1_admin: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.get(
'/api/config',
content_type='application/json',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -91,26 +69,18 @@ class TestGetConfig:
assert 'Error on getting configuration.' in data['message']
class TestUpdateConfig:
class TestUpdateConfig(ApiTestCaseMixin):
def test_it_updates_config_when_user_is_admin(
self, app: Flask, user_1_admin: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(dict(gpx_limit_import=100, max_users=10)),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -125,13 +95,8 @@ class TestUpdateConfig:
def test_it_updates_all_config(
self, app: Flask, user_1_admin: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.patch(
@ -145,10 +110,7 @@ class TestUpdateConfig:
max_users=50,
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -163,21 +125,13 @@ class TestUpdateConfig:
def test_it_returns_403_when_user_is_not_an_admin(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(dict(gpx_limit_import=100, max_users=10)),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -189,23 +143,15 @@ class TestUpdateConfig:
def test_it_returns_400_if_invalid_is_payload(
self, app: Flask, user_1_admin: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(dict()),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -216,26 +162,125 @@ class TestUpdateConfig:
def test_it_returns_error_on_update_if_application_has_no_config(
self, app_no_config: Flask, user_1_admin: User
) -> None:
client = app_no_config.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app_no_config, as_admin=True
)
response = client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(dict(gpx_limit_import=100, max_users=10)),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
assert response.status_code == 500
assert 'error' in data['status']
assert 'Error on updating configuration.' in data['message']
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, as_admin=True
)
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}'),
)
data = json.loads(response.data.decode())
assert response.status_code == 400
assert 'error' in data['status']
assert (
'Max. size of zip archive must be equal or greater than max. size '
'of uploaded files'
) in data['message']
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, as_admin=True
)
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}'),
)
data = json.loads(response.data.decode())
assert response.status_code == 400
assert 'error' in data['status']
assert (
'Max. size of zip archive must be greater than 0'
in data['message']
)
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, as_admin=True
)
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}'),
)
data = json.loads(response.data.decode())
assert response.status_code == 400
assert 'error' in data['status']
assert (
'Max. size of uploaded files must be greater than 0'
in data['message']
)
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, as_admin=True
)
response = client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(
dict(
gpx_limit_import=0,
)
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
assert response.status_code == 400
assert 'error' in data['status']
assert (
'Max. files in a zip archive must be greater than 0'
in data['message']
)

View File

@ -1,5 +1,5 @@
import os
from typing import Generator, Optional
from typing import Generator, Optional, Union
import pytest
@ -11,13 +11,24 @@ from fittrackee.application.utils import update_app_config_from_database
def get_app_config(
with_config: Optional[bool] = False,
max_workouts: Optional[int] = None,
max_single_file_size: Optional[Union[int, float]] = None,
max_zip_file_size: Optional[Union[int, float]] = None,
max_users: Optional[int] = None,
) -> Optional[AppConfig]:
if with_config:
config = AppConfig()
config.gpx_limit_import = 10 if max_workouts is None else max_workouts
config.max_single_file_size = 1 * 1024 * 1024
config.max_zip_file_size = 1 * 1024 * 1024 * 10
config.max_users = 100
config.max_single_file_size = (
(1 if max_single_file_size is None else max_single_file_size)
* 1024
* 1024
)
config.max_zip_file_size = (
(10 if max_zip_file_size is None else max_zip_file_size)
* 1024
* 1024
)
config.max_users = 100 if max_users is None else max_users
db.session.add(config)
db.session.commit()
return config
@ -27,12 +38,21 @@ def get_app_config(
def get_app(
with_config: Optional[bool] = False,
max_workouts: Optional[int] = None,
max_single_file_size: Optional[Union[int, float]] = None,
max_zip_file_size: Optional[Union[int, float]] = None,
max_users: Optional[int] = None,
) -> Generator:
app = create_app()
with app.app_context():
try:
db.create_all()
app_db_config = get_app_config(with_config, max_workouts)
app_db_config = get_app_config(
with_config,
max_workouts,
max_single_file_size,
max_zip_file_size,
max_users,
)
if app_db_config:
update_app_config_from_database(app, app_db_config)
yield app
@ -64,6 +84,32 @@ def app_with_max_workouts(monkeypatch: pytest.MonkeyPatch) -> Generator:
yield from get_app(with_config=True, max_workouts=2)
@pytest.fixture
def app_with_max_file_size_equals_0(
monkeypatch: pytest.MonkeyPatch,
) -> Generator:
monkeypatch.setenv('EMAIL_URL', 'smtp://none:none@0.0.0.0:1025')
yield from get_app(with_config=True, max_single_file_size=0)
@pytest.fixture
def app_with_max_file_size(monkeypatch: pytest.MonkeyPatch) -> Generator:
monkeypatch.setenv('EMAIL_URL', 'smtp://none:none@0.0.0.0:1025')
yield from get_app(with_config=True, max_single_file_size=0.001)
@pytest.fixture
def app_with_max_zip_file_size(monkeypatch: pytest.MonkeyPatch) -> Generator:
monkeypatch.setenv('EMAIL_URL', 'smtp://none:none@0.0.0.0:1025')
yield from get_app(with_config=True, max_zip_file_size=0.001)
@pytest.fixture
def app_with_3_users_max(monkeypatch: pytest.MonkeyPatch) -> Generator:
monkeypatch.setenv('EMAIL_URL', 'smtp://none:none@0.0.0.0:1025')
yield from get_app(with_config=True, max_users=3)
@pytest.fixture
def app_no_config() -> Generator:
yield from get_app(with_config=False)

View File

@ -3,10 +3,8 @@ from uuid import uuid4
import pytest
from fittrackee.users.utils import (
display_readable_file_size,
get_readable_duration,
)
from fittrackee.responses import display_readable_file_size
from fittrackee.utils import get_readable_duration
class TestDisplayReadableFileSize:

View File

@ -10,6 +10,8 @@ from fittrackee.users.models import User
from fittrackee.users.utils_token import get_user_token
from fittrackee.workouts.models import Sport, Workout
from ..api_test_case import ApiTestCaseMixin
class TestUserRegistration:
def test_user_can_register(self, app: Flask) -> None:
@ -356,21 +358,14 @@ class TestUserLogin:
assert data['message'] == 'Invalid credentials.'
class TestUserLogout:
class TestUserLogout(ApiTestCaseMixin):
def test_user_can_logout(self, app: Flask, user_1: User) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/auth/logout',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -381,20 +376,13 @@ class TestUserLogout:
def test_it_returns_error_with_expired_token(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
now = datetime.utcnow()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
with freeze_time(now + timedelta(seconds=4)):
response = client.get(
'/api/auth/logout',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
assert data['status'] == 'error'
@ -420,23 +408,17 @@ class TestUserLogout:
assert response.status_code == 401
class TestUserProfile:
class TestUserProfile(ApiTestCaseMixin):
def test_it_returns_user_minimal_profile(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/auth/profile',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
assert data['status'] == 'success'
assert data['data'] is not None
@ -457,19 +439,13 @@ class TestUserProfile:
def test_it_returns_user_full_profile(
self, app: Flask, user_1_full: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/auth/profile',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
assert data['status'] == 'success'
assert data['data'] is not None
@ -501,19 +477,13 @@ class TestUserProfile:
workout_cycling_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/auth/profile',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
assert data['status'] == 'success'
assert data['data'] is not None
@ -540,14 +510,10 @@ class TestUserProfile:
assert response.status_code == 401
class TestUserProfileUpdate:
class TestUserProfileUpdate(ApiTestCaseMixin):
def test_it_updates_user_profile(self, app: Flask, user_1: User) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/auth/profile/edit',
content_type='application/json',
@ -565,11 +531,9 @@ class TestUserProfileUpdate:
language='fr',
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
assert data['status'] == 'success'
assert data['message'] == 'User profile updated.'
@ -595,12 +559,8 @@ class TestUserProfileUpdate:
def test_it_updates_user_profile_without_password(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/auth/profile/edit',
content_type='application/json',
@ -616,11 +576,9 @@ class TestUserProfileUpdate:
language='fr',
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
assert data['status'] == 'success'
assert data['message'] == 'User profile updated.'
@ -646,21 +604,15 @@ class TestUserProfileUpdate:
def test_it_returns_error_if_fields_are_missing(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/auth/profile/edit',
content_type='application/json',
data=json.dumps(dict(first_name='John')),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
assert data['status'] == 'error'
assert data['message'] == 'Invalid payload.'
@ -669,21 +621,15 @@ class TestUserProfileUpdate:
def test_it_returns_error_if_payload_is_empty(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/auth/profile/edit',
content_type='application/json',
data=json.dumps(dict()),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
assert response.status_code == 400
assert 'Invalid payload.' in data['message']
@ -692,12 +638,8 @@ class TestUserProfileUpdate:
def test_it_returns_error_if_passwords_mismatch(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/auth/profile/edit',
content_type='application/json',
@ -715,11 +657,9 @@ class TestUserProfileUpdate:
language='en',
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
assert data['status'] == 'error'
assert (
@ -731,12 +671,8 @@ class TestUserProfileUpdate:
def test_it_returns_error_if_password_confirmation_is_missing(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/auth/profile/edit',
content_type='application/json',
@ -753,11 +689,9 @@ class TestUserProfileUpdate:
language='en',
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
assert data['status'] == 'error'
assert (
@ -767,23 +701,19 @@ class TestUserProfileUpdate:
assert response.status_code == 400
class TestUserPicture:
class TestUserPicture(ApiTestCaseMixin):
def test_it_updates_user_picture(self, app: Flask, user_1: User) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/auth/picture',
data=dict(file=(BytesIO(b'avatar'), 'avatar.png')),
headers=dict(
content_type='multipart/form-data',
authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
data = json.loads(response.data.decode())
assert data['status'] == 'success'
assert data['message'] == 'User picture updated.'
@ -795,10 +725,10 @@ class TestUserPicture:
data=dict(file=(BytesIO(b'avatar2'), 'avatar2.png')),
headers=dict(
content_type='multipart/form-data',
authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
data = json.loads(response.data.decode())
assert data['status'] == 'success'
assert data['message'] == 'User picture updated.'
@ -809,20 +739,16 @@ class TestUserPicture:
def test_it_returns_error_if_file_is_missing(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/auth/picture',
headers=dict(
content_type='multipart/form-data',
authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
data = json.loads(response.data.decode())
assert data['status'] == 'fail'
assert data['message'] == 'No file part.'
@ -831,49 +757,96 @@ class TestUserPicture:
def test_it_returns_error_if_file_is_invalid(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/auth/picture',
data=dict(file=(BytesIO(b'avatar'), 'avatar.bmp')),
headers=dict(
content_type='multipart/form-data',
authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
data = json.loads(response.data.decode())
assert data['status'] == 'fail'
assert data['message'] == 'File extension not allowed.'
assert response.status_code == 400
def test_it_returns_error_if_image_size_exceeds_file_limit(
self,
app_with_max_file_size: Flask,
user_1: User,
sport_1_cycling: Sport,
gpx_file: str,
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app_with_max_file_size
)
response = client.post(
'/api/auth/picture',
data=dict(
file=(BytesIO(b'test_file_for_avatar' * 50), 'avatar.jpg')
),
headers=dict(
content_type='multipart/form-data',
Authorization=f'Bearer {auth_token}',
),
)
data = json.loads(response.data.decode())
print('data', data)
assert response.status_code == 413
assert 'fail' in data['status']
assert (
'Error during picture upload, file size (1.2KB) exceeds 1.0KB.'
in data['message']
)
assert 'data' not in data
def test_it_returns_error_if_image_size_exceeds_archive_limit(
self,
app_with_max_zip_file_size: Flask,
user_1: User,
sport_1_cycling: Sport,
gpx_file: str,
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app_with_max_zip_file_size
)
response = client.post(
'/api/auth/picture',
data=dict(
file=(BytesIO(b'test_file_for_avatar' * 50), 'avatar.jpg')
),
headers=dict(
content_type='multipart/form-data',
Authorization=f'Bearer {auth_token}',
),
)
data = json.loads(response.data.decode())
print('data', data)
assert response.status_code == 413
assert 'fail' in data['status']
assert (
'Error during picture upload, file size (1.2KB) exceeds 1.0KB.'
in data['message']
)
assert 'data' not in data
class TestRegistrationConfiguration:
def test_it_returns_error_if_it_exceeds_max_users(
self, app: Flask, user_1_admin: User, user_2: User, user_3: User
self,
app_with_3_users_max: Flask,
user_1_admin: User,
user_2: User,
user_3: User,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
)
client.patch(
'/api/config',
content_type='application/json',
data=json.dumps(dict(max_users=3, registration=True)),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
)
client = app_with_3_users_max.test_client()
response = client.post(
'/api/auth/register',
@ -896,13 +869,11 @@ class TestRegistrationConfiguration:
def test_it_disables_registration_on_user_registration(
self,
app_no_config: Flask,
app_config: Flask,
app_with_3_users_max: Flask,
user_1_admin: User,
user_2: User,
) -> None:
app_config.max_users = 3
client = app_no_config.test_client()
client = app_with_3_users_max.test_client()
client.post(
'/api/auth/register',
data=json.dumps(
@ -915,6 +886,7 @@ class TestRegistrationConfiguration:
),
content_type='application/json',
)
response = client.post(
'/api/auth/register',
data=json.dumps(
@ -927,6 +899,7 @@ class TestRegistrationConfiguration:
),
content_type='application/json',
)
assert response.status_code == 403
data = json.loads(response.data.decode())
assert data['status'] == 'error'
@ -934,13 +907,10 @@ class TestRegistrationConfiguration:
def test_it_does_not_disable_registration_on_user_registration(
self,
app_no_config: Flask,
app_config: Flask,
user_1_admin: User,
user_2: User,
app_with_3_users_max: Flask,
user_1: User,
) -> None:
app_config.max_users = 4
client = app_no_config.test_client()
client = app_with_3_users_max.test_client()
client.post(
'/api/auth/register',
data=json.dumps(

View File

@ -8,25 +8,19 @@ from flask import Flask
from fittrackee.users.models import User
from fittrackee.workouts.models import Sport, Workout
from ..api_test_case import ApiTestCaseMixin
class TestGetUser:
class TestGetUser(ApiTestCaseMixin):
def test_it_gets_single_user_without_workouts(
self, app: Flask, user_1: User, user_2: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/users/{user_2.username}',
content_type='application/json',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -61,20 +55,12 @@ class TestGetUser:
workout_cycling_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/users/{user_1.username}',
content_type='application/json',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -103,19 +89,12 @@ class TestGetUser:
def test_it_returns_error_if_user_does_not_exist(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/users/not_existing',
content_type='application/json',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -124,23 +103,15 @@ class TestGetUser:
assert 'User does not exist.' in data['message']
class TestGetUsers:
class TestGetUsers(ApiTestCaseMixin):
def test_it_get_users_list(
self, app: Flask, user_1: User, user_2: User, user_3: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/users',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -200,19 +171,11 @@ class TestGetUsers:
workout_running_user_1: Workout,
workout_cycling_user_2: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/users',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -265,19 +228,11 @@ class TestGetUsers:
user_2: User,
user_3: User,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/users?page=1',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -300,19 +255,11 @@ class TestGetUsers:
user_2: User,
user_3: User,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/users?page=2',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -334,19 +281,11 @@ class TestGetUsers:
user_2: User,
user_3: User,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/users?page=2',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -368,19 +307,11 @@ class TestGetUsers:
user_2: User,
user_3: User,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/users?per_page=2',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -402,19 +333,11 @@ class TestGetUsers:
user_2: User,
user_3: User,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/users?page=2&per_page=2',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -432,18 +355,11 @@ class TestGetUsers:
def test_it_gets_users_list_ordered_by_username(
self, app: Flask, user_1: User, user_2: User, user_3: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/users?order_by=username',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -464,19 +380,11 @@ class TestGetUsers:
def test_it_gets_users_list_ordered_by_username_ascending(
self, app: Flask, user_1: User, user_2: User, user_3: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/users?order_by=username&order=asc',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -497,19 +405,11 @@ class TestGetUsers:
def test_it_gets_users_list_ordered_by_username_descending(
self, app: Flask, user_1: User, user_2: User, user_3: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/users?order_by=username&order=desc',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -533,21 +433,13 @@ class TestGetUsers:
user_2.created_at = datetime.utcnow() - timedelta(days=1)
user_3.created_at = datetime.utcnow() - timedelta(hours=1)
user_1_admin.created_at = datetime.utcnow()
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.get(
'/api/users?order_by=created_at',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -571,21 +463,13 @@ class TestGetUsers:
user_2.created_at = datetime.utcnow() - timedelta(days=1)
user_3.created_at = datetime.utcnow() - timedelta(hours=1)
user_1_admin.created_at = datetime.utcnow()
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.get(
'/api/users?order_by=created_at&order=asc',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -609,21 +493,13 @@ class TestGetUsers:
user_2.created_at = datetime.utcnow() - timedelta(days=1)
user_3.created_at = datetime.utcnow() - timedelta(hours=1)
user_1_admin.created_at = datetime.utcnow()
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.get(
'/api/users?order_by=created_at&order=desc',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -644,21 +520,13 @@ class TestGetUsers:
def test_it_gets_users_list_ordered_by_admin_rights(
self, app: Flask, user_2: User, user_1_admin: User, user_3: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.get(
'/api/users?order_by=admin',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -679,21 +547,13 @@ class TestGetUsers:
def test_it_gets_users_list_ordered_by_admin_rights_ascending(
self, app: Flask, user_2: User, user_1_admin: User, user_3: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.get(
'/api/users?order_by=admin&order=asc',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -714,21 +574,13 @@ class TestGetUsers:
def test_it_gets_users_list_ordered_by_admin_rights_descending(
self, app: Flask, user_2: User, user_3: User, user_1_admin: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.get(
'/api/users?order_by=admin&order=desc',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -755,19 +607,11 @@ class TestGetUsers:
sport_1_cycling: Sport,
workout_cycling_user_2: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/users?order_by=workouts_count',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -797,19 +641,11 @@ class TestGetUsers:
sport_1_cycling: Sport,
workout_cycling_user_2: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/users?order_by=workouts_count&order=asc',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -839,19 +675,11 @@ class TestGetUsers:
sport_1_cycling: Sport,
workout_cycling_user_2: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/users?order_by=workouts_count&order=desc',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -875,19 +703,11 @@ class TestGetUsers:
def test_it_gets_users_list_filtering_on_username(
self, app: Flask, user_1: User, user_2: User, user_3: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/users?q=toto',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -906,19 +726,11 @@ class TestGetUsers:
def test_it_returns_empty_users_list_filtering_on_username(
self, app: Flask, user_1: User, user_2: User, user_3: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/users?q=not_existing',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -936,19 +748,11 @@ class TestGetUsers:
def test_it_users_list_with_complex_query(
self, app: Flask, user_1: User, user_2: User, user_3: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/users?order_by=username&order=desc&page=2&per_page=2',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -991,27 +795,19 @@ class TestGetUserPicture:
assert 'User does not exist.' in data['message']
class TestUpdateUser:
class TestUpdateUser(ApiTestCaseMixin):
def test_it_adds_admin_rights_to_a_user(
self, app: Flask, user_1_admin: User, user_2: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.patch(
'/api/users/toto',
content_type='application/json',
data=json.dumps(dict(admin=True)),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1025,23 +821,15 @@ class TestUpdateUser:
def test_it_removes_admin_rights_to_a_user(
self, app: Flask, user_1_admin: User, user_2: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.patch(
'/api/users/toto',
content_type='application/json',
data=json.dumps(dict(admin=False)),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1056,23 +844,15 @@ class TestUpdateUser:
def test_it_returns_error_if_payload_for_admin_rights_is_empty(
self, app: Flask, user_1_admin: User, user_2: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.patch(
'/api/users/toto',
content_type='application/json',
data=json.dumps(dict()),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1083,23 +863,15 @@ class TestUpdateUser:
def test_it_returns_error_if_payload_for_admin_rights_is_invalid(
self, app: Flask, user_1_admin: User, user_2: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.patch(
'/api/users/toto',
content_type='application/json',
data=json.dumps(dict(admin="")),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1113,21 +885,13 @@ class TestUpdateUser:
def test_it_returns_error_if_user_can_not_change_admin_rights(
self, app: Flask, user_1: User, user_2: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.patch(
'/api/users/toto',
content_type='application/json',
data=json.dumps(dict(admin=True)),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1136,23 +900,15 @@ class TestUpdateUser:
assert 'You do not have permissions.' in data['message']
class TestDeleteUser:
class TestDeleteUser(ApiTestCaseMixin):
def test_user_can_delete_its_own_account(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.delete(
'/api/users/test',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
assert response.status_code == 204
@ -1160,12 +916,7 @@ class TestDeleteUser:
def test_user_with_workout_can_delete_its_own_account(
self, app: Flask, user_1: User, sport_1_cycling: Sport, gpx_file: str
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
client.post(
'/api/workouts',
data=dict(
@ -1174,17 +925,13 @@ class TestDeleteUser:
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
response = client.delete(
'/api/users/test',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
assert response.status_code == 204
@ -1192,28 +939,19 @@ class TestDeleteUser:
def test_user_with_picture_can_delete_its_own_account(
self, app: Flask, user_1: User, sport_1_cycling: Sport, gpx_file: str
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
client.post(
'/api/auth/picture',
data=dict(file=(BytesIO(b'avatar'), 'avatar.png')),
headers=dict(
content_type='multipart/form-data',
authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
response = client.delete(
'/api/users/test',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
assert response.status_code == 204
@ -1221,19 +959,11 @@ class TestDeleteUser:
def test_user_can_not_delete_another_user_account(
self, app: Flask, user_1: User, user_2: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.delete(
'/api/users/toto',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1244,19 +974,11 @@ class TestDeleteUser:
def test_it_returns_error_when_deleting_non_existing_user(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.delete(
'/api/users/not_existing',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1267,21 +989,13 @@ class TestDeleteUser:
def test_admin_can_delete_another_user_account(
self, app: Flask, user_1_admin: User, user_2: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.delete(
'/api/users/toto',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
assert response.status_code == 204
@ -1289,21 +1003,13 @@ class TestDeleteUser:
def test_admin_can_delete_its_own_account(
self, app: Flask, user_1_admin: User, user_2_admin: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.delete(
'/api/users/admin',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
assert response.status_code == 204
@ -1311,20 +1017,13 @@ class TestDeleteUser:
def test_admin_can_not_delete_its_own_account_if_no_other_admin(
self, app: Flask, user_1_admin: User, user_2: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.delete(
'/api/users/admin',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1337,29 +1036,19 @@ class TestDeleteUser:
def test_it_enables_registration_on_user_delete(
self,
app_no_config: Flask,
app_config: Flask,
app_with_3_users_max: Flask,
user_1_admin: User,
user_2: User,
user_3: User,
) -> None:
app_config.max_users = 3
client = app_no_config.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app_with_3_users_max, as_admin=True
)
client.delete(
'/api/users/toto',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
response = client.post(
'/api/auth/register',
data=json.dumps(
@ -1376,28 +1065,19 @@ class TestDeleteUser:
def test_it_does_not_enable_registration_on_user_delete(
self,
app_no_config: Flask,
app_config: Flask,
app_with_3_users_max: Flask,
user_1_admin: User,
user_2: User,
user_3: User,
user_1_paris: User,
) -> None:
app_config.max_users = 2
client = app_no_config.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app_with_3_users_max, as_admin=True
)
client.delete(
'/api/users/toto',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
response = client.post(
'/api/auth/register',

View File

@ -5,8 +5,10 @@ from flask import Flask
from fittrackee.users.models import User
from fittrackee.workouts.models import Sport, Workout
from ..api_test_case import ApiTestCaseMixin
class TestGetRecords:
class TestGetRecords(ApiTestCaseMixin):
def test_it_gets_records_for_authenticated_user(
self,
app: Flask,
@ -17,21 +19,14 @@ class TestGetRecords:
workout_cycling_user_1: Workout,
workout_cycling_user_2: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/records',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['records']) == 4
@ -97,21 +92,14 @@ class TestGetRecords:
sport_2_running: Sport,
workout_cycling_user_2: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/records',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['records']) == 0
@ -123,12 +111,8 @@ class TestGetRecords:
sport_1_cycling: Sport,
sport_2_running: Sport,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
client.post(
'/api/workouts/no_gpx',
content_type='application/json',
@ -141,20 +125,15 @@ class TestGetRecords:
title='Workout test',
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
response = client.get(
'/api/records',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['records']) == 0
@ -162,12 +141,7 @@ class TestGetRecords:
def test_it_gets_updated_records_after_workouts_post_and_patch(
self, app: Flask, user_1: User, sport_1_cycling: Sport
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts/no_gpx',
content_type='application/json',
@ -180,26 +154,20 @@ class TestGetRecords:
title='Workout test 1',
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
workout_1_short_id = data['data']['workouts'][0]['id']
response = client.get(
'/api/records',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['records']) == 4
assert (
'Mon, 14 May 2018 14:05:00 GMT'
== data['data']['records'][0]['workout_date']
@ -254,19 +222,13 @@ class TestGetRecords:
title='Workout test 2',
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
workout_2_short_id = data['data']['workouts'][0]['id']
response = client.get(
'/api/records',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -327,19 +289,13 @@ class TestGetRecords:
title='Workout test 3',
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
workout_3_short_id = data['data']['workouts'][0]['id']
response = client.get(
'/api/records',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -393,17 +349,11 @@ class TestGetRecords:
f'/api/workouts/{workout_3_short_id}',
content_type='application/json',
data=json.dumps(dict(duration=4000)),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
response = client.get(
'/api/records',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -454,17 +404,11 @@ class TestGetRecords:
# delete workout 2 => AS and MS record update
client.delete(
f'/api/workouts/{workout_2_short_id}',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
response = client.get(
'/api/records',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -526,19 +470,13 @@ class TestGetRecords:
title='Workout test 4',
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
workout_4_short_id = data['data']['workouts'][0]['id']
response = client.get(
'/api/records',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -602,19 +540,13 @@ class TestGetRecords:
title='Workout test 5',
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
workout_5_short_id = data['data']['workouts'][0]['id']
response = client.get(
'/api/records',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -665,38 +597,23 @@ class TestGetRecords:
# delete all workouts - no more records
client.delete(
f'/api/workouts/{workout_1_short_id}',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
client.delete(
f'/api/workouts/{workout_3_short_id}',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
client.delete(
f'/api/workouts/{workout_4_short_id}',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
client.delete(
f'/api/workouts/{workout_5_short_id}',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
response = client.get(
'/api/records',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -711,12 +628,8 @@ class TestGetRecords:
sport_1_cycling: Sport,
sport_2_running: Sport,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts/no_gpx',
content_type='application/json',
@ -729,10 +642,7 @@ class TestGetRecords:
title='Workout test 1',
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
workout_1_short_id = data['data']['workouts'][0]['id']
@ -748,10 +658,7 @@ class TestGetRecords:
title='Workout test 2',
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
workout_2_short_id = data['data']['workouts'][0]['id']
@ -767,10 +674,7 @@ class TestGetRecords:
title='Workout test 3',
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
response = client.post(
'/api/workouts/no_gpx',
@ -784,19 +688,13 @@ class TestGetRecords:
title='Workout test 4',
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
workout_4_short_id = data['data']['workouts'][0]['id']
response = client.get(
'/api/records',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -888,17 +786,11 @@ class TestGetRecords:
f'/api/workouts/{workout_2_short_id}',
content_type='application/json',
data=json.dumps(dict(sport_id=1)),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
response = client.get(
'/api/records',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())

View File

@ -5,6 +5,8 @@ from flask import Flask
from fittrackee.users.models import User
from fittrackee.workouts.models import Sport, Workout
from ..api_test_case import ApiTestCaseMixin
expected_sport_1_cycling_result = {
'id': 1,
'label': 'Cycling',
@ -35,7 +37,7 @@ expected_sport_1_cycling_inactive_admin_result = (
expected_sport_1_cycling_inactive_admin_result['has_workouts'] = False
class TestGetSports:
class TestGetSports(ApiTestCaseMixin):
def test_it_gets_all_sports(
self,
app: Flask,
@ -43,19 +45,11 @@ class TestGetSports:
sport_1_cycling: Sport,
sport_2_running: Sport,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/sports',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -72,19 +66,11 @@ class TestGetSports:
sport_1_cycling_inactive: Sport,
sport_2_running: Sport,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/sports',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -104,21 +90,13 @@ class TestGetSports:
sport_1_cycling_inactive: Sport,
sport_2_running: Sport,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.get(
'/api/sports',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -134,23 +112,15 @@ class TestGetSports:
)
class TestGetSport:
class TestGetSport(ApiTestCaseMixin):
def test_it_gets_a_sport(
self, app: Flask, user_1: User, sport_1_cycling: Sport
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/sports/1',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -162,19 +132,11 @@ class TestGetSport:
def test_it_returns_404_if_sport_does_not_exist(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/sports/1',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -185,24 +147,16 @@ class TestGetSport:
def test_it_gets_a_inactive_sport(
self, app: Flask, user_1: User, sport_1_cycling_inactive: Sport
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/sports/1',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['sports']) == 1
assert (
data['data']['sports'][0]
@ -212,26 +166,18 @@ class TestGetSport:
def test_it_get_an_inactive_sport_with_admin_rights(
self, app: Flask, user_1_admin: User, sport_1_cycling_inactive: Sport
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.get(
'/api/sports/1',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['sports']) == 1
assert (
data['data']['sports'][0]
@ -239,27 +185,19 @@ class TestGetSport:
)
class TestUpdateSport:
class TestUpdateSport(ApiTestCaseMixin):
def test_it_disables_a_sport(
self, app: Flask, user_1_admin: User, sport_1_cycling: Sport
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.patch(
'/api/sports/1',
content_type='application/json',
data=json.dumps(dict(is_active=False)),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -273,23 +211,15 @@ class TestUpdateSport:
self, app: Flask, user_1_admin: User, sport_1_cycling: Sport
) -> None:
sport_1_cycling.is_active = False
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.patch(
'/api/sports/1',
content_type='application/json',
data=json.dumps(dict(is_active=True)),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -306,23 +236,15 @@ class TestUpdateSport:
sport_1_cycling: Sport,
workout_cycling_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.patch(
'/api/sports/1',
content_type='application/json',
data=json.dumps(dict(is_active=False)),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -340,23 +262,15 @@ class TestUpdateSport:
workout_cycling_user_1: Workout,
) -> None:
sport_1_cycling.is_active = False
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.patch(
'/api/sports/1',
content_type='application/json',
data=json.dumps(dict(is_active=True)),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -369,23 +283,16 @@ class TestUpdateSport:
def test_returns_error_if_user_has_no_admin_rights(
self, app: Flask, user_1: User, sport_1_cycling: Sport
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.patch(
'/api/sports/1',
content_type='application/json',
data=json.dumps(dict(is_active=False)),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
data = json.loads(response.data.decode())
assert response.status_code == 403
assert 'success' not in data['status']
assert 'error' in data['status']
@ -394,23 +301,15 @@ class TestUpdateSport:
def test_returns_error_if_payload_is_invalid(
self, app: Flask, user_1_admin: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.patch(
'/api/sports/1',
content_type='application/json',
data=json.dumps(dict()),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -421,25 +320,18 @@ class TestUpdateSport:
def test_it_returns_error_if_sport_does_not_exist(
self, app: Flask, user_1_admin: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.patch(
'/api/sports/1',
content_type='application/json',
data=json.dumps(dict(is_active=False)),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
data = json.loads(response.data.decode())
assert response.status_code == 404
assert 'not found' in data['status']
assert len(data['data']['sports']) == 0

View File

@ -5,24 +5,18 @@ from flask import Flask
from fittrackee.users.models import User
from fittrackee.workouts.models import Sport, Workout
from ..api_test_case import ApiTestCaseMixin
class TestGetStatsByTime:
class TestGetStatsByTime(ApiTestCaseMixin):
def test_it_gets_no_stats_when_user_has_no_workouts(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/stats/{user_1.username}/by_time',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -33,19 +27,11 @@ class TestGetStatsByTime:
def test_it_returns_error_when_user_does_not_exists(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/stats/1000/by_time',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -62,19 +48,14 @@ class TestGetStatsByTime:
seven_workouts_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/stats/{user_1.username}/by_time?from="2018-04-01&to=2018-04-30', # noqa
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
(
f'/api/stats/{user_1.username}/by_time'
f'?from="2018-04-01&to=2018-04-30'
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -94,19 +75,11 @@ class TestGetStatsByTime:
seven_workouts_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/stats/{user_1.username}/by_time?from=2018-04-01&to=2018-04-30&time=day', # noqa
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -123,19 +96,11 @@ class TestGetStatsByTime:
seven_workouts_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/stats/{user_1.username}/by_time',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -172,19 +137,11 @@ class TestGetStatsByTime:
seven_workouts_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/stats/{user_1.username}/by_time?from=2018-04-01&to=2018-04-30', # noqa
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -214,20 +171,12 @@ class TestGetStatsByTime:
seven_workouts_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/stats/{user_1_paris.username}/by_time?'
f'from=2018-04-01&to=2018-04-30',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -257,19 +206,11 @@ class TestGetStatsByTime:
seven_workouts_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/stats/{user_1.username}/by_time?time=year',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -306,19 +247,11 @@ class TestGetStatsByTime:
seven_workouts_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/stats/{user_1.username}/by_time?from=2018-04-01&to=2018-04-30&time=year', # noqa
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -348,19 +281,12 @@ class TestGetStatsByTime:
seven_workouts_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/stats/{user_1_paris.username}/by_time?from=2018-04-01&to=2018-04-30&time=year', # noqa
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -390,19 +316,11 @@ class TestGetStatsByTime:
seven_workouts_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/stats/{user_1.username}/by_time?time=month',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -467,19 +385,11 @@ class TestGetStatsByTime:
seven_workouts_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/stats/{user_1_full.username}/by_time?time=month',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -544,19 +454,11 @@ class TestGetStatsByTime:
seven_workouts_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/stats/{user_1.username}/by_time?from=2018-04-01&to=2018-04-30&time=month', # noqa
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -586,19 +488,11 @@ class TestGetStatsByTime:
seven_workouts_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/stats/{user_1_full.username}/by_time?time=week',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -663,19 +557,11 @@ class TestGetStatsByTime:
seven_workouts_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/stats/{user_1.username}/by_time?from=2018-04-01&to=2018-04-30&time=week', # noqa
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -705,19 +591,11 @@ class TestGetStatsByTime:
seven_workouts_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/stats/{user_1.username}/by_time?time=weekm',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -782,19 +660,11 @@ class TestGetStatsByTime:
seven_workouts_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/stats/{user_1.username}/by_time?from=2018-04-01&to=2018-04-30&time=weekm', # noqa
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -816,7 +686,7 @@ class TestGetStatsByTime:
}
class TestGetStatsBySport:
class TestGetStatsBySport(ApiTestCaseMixin):
def test_it_gets_stats_by_sport(
self,
app: Flask,
@ -826,19 +696,11 @@ class TestGetStatsBySport:
seven_workouts_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/stats/{user_1.username}/by_sport',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -866,19 +728,11 @@ class TestGetStatsBySport:
seven_workouts_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/stats/{user_1.username}/by_sport?sport_id=1',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -901,19 +755,11 @@ class TestGetStatsBySport:
seven_workouts_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/stats/1000/by_sport?sport_id=1',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -930,19 +776,11 @@ class TestGetStatsBySport:
seven_workouts_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/stats/{user_1.username}/by_sport?sport_id=999',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -959,19 +797,11 @@ class TestGetStatsBySport:
seven_workouts_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/stats/{user_1.username}/by_sport?sport_id="999',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -983,25 +813,17 @@ class TestGetStatsBySport:
)
class TestGetAllStats:
class TestGetAllStats(ApiTestCaseMixin):
def test_it_returns_all_stats_when_users_have_no_workouts(
self, app: Flask, user_1_admin: User, user_2: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.get(
'/api/stats/all',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1024,21 +846,13 @@ class TestGetAllStats:
workout_cycling_user_2: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app, as_admin=True
)
response = client.get(
'/api/stats/all',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1061,19 +875,11 @@ class TestGetAllStats:
workout_cycling_user_2: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/stats/all',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())

View File

@ -7,10 +7,11 @@ from flask import Flask
from fittrackee.users.models import User
from fittrackee.workouts.models import Sport, Workout
from ..api_test_case import ApiTestCaseMixin
from .utils import get_random_short_id
class TestGetWorkouts:
class TestGetWorkouts(ApiTestCaseMixin):
def test_it_gets_all_workouts_for_authenticated_user(
self,
app: Flask,
@ -22,19 +23,11 @@ class TestGetWorkouts:
workout_cycling_user_2: Workout,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -104,7 +97,7 @@ class TestGetWorkouts:
assert 'Provide a valid auth token.' in data['message']
class TestGetWorkoutsWithPagination:
class TestGetWorkoutsWithPagination(ApiTestCaseMixin):
def test_it_gets_workouts_with_default_pagination(
self,
app: Flask,
@ -112,19 +105,11 @@ class TestGetWorkoutsWithPagination:
sport_1_cycling: Sport,
seven_workouts_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -151,19 +136,11 @@ class TestGetWorkoutsWithPagination:
sport_1_cycling: Sport,
seven_workouts_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts?page=1',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -190,19 +167,11 @@ class TestGetWorkoutsWithPagination:
sport_1_cycling: Sport,
seven_workouts_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts?page=2',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -229,19 +198,11 @@ class TestGetWorkoutsWithPagination:
sport_1_cycling: Sport,
seven_workouts_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts?page=3',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -256,19 +217,11 @@ class TestGetWorkoutsWithPagination:
sport_1_cycling: Sport,
seven_workouts_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts?page=A',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -287,19 +240,11 @@ class TestGetWorkoutsWithPagination:
sport_1_cycling: Sport,
seven_workouts_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts?per_page=10',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -323,19 +268,11 @@ class TestGetWorkoutsWithPagination:
sport_1_cycling: Sport,
seven_workouts_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts?per_page=3',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -352,7 +289,7 @@ class TestGetWorkoutsWithPagination:
)
class TestGetWorkoutsWithOrder:
class TestGetWorkoutsWithOrder(ApiTestCaseMixin):
def test_it_gets_workouts_with_default_order(
self,
app: Flask,
@ -360,19 +297,11 @@ class TestGetWorkoutsWithOrder:
sport_1_cycling: Sport,
seven_workouts_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -395,19 +324,11 @@ class TestGetWorkoutsWithOrder:
sport_1_cycling: Sport,
seven_workouts_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts?order=asc',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -430,19 +351,11 @@ class TestGetWorkoutsWithOrder:
sport_1_cycling: Sport,
seven_workouts_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts?order=desc',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -459,7 +372,7 @@ class TestGetWorkoutsWithOrder:
)
class TestGetWorkoutsWithFilters:
class TestGetWorkoutsWithFilters(ApiTestCaseMixin):
def test_it_gets_workouts_with_date_filter(
self,
app: Flask,
@ -467,19 +380,11 @@ class TestGetWorkoutsWithFilters:
sport_1_cycling: Sport,
seven_workouts_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts?from=2018-02-01&to=2018-02-28',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -506,19 +411,11 @@ class TestGetWorkoutsWithFilters:
sport_1_cycling: Sport,
seven_workouts_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts?from=2018-03-01&to=2018-03-30',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -533,19 +430,11 @@ class TestGetWorkoutsWithFilters:
sport_1_cycling: Sport,
seven_workouts_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts?from=2018-04-01',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -569,19 +458,11 @@ class TestGetWorkoutsWithFilters:
sport_1_cycling: Sport,
seven_workouts_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts?to=2017-12-31',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -604,19 +485,11 @@ class TestGetWorkoutsWithFilters:
sport_1_cycling: Sport,
seven_workouts_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts?distance_from=5&distance_to=8',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -639,19 +512,11 @@ class TestGetWorkoutsWithFilters:
sport_1_cycling: Sport,
seven_workouts_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts?duration_from=00:52&duration_to=01:20',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -670,19 +535,11 @@ class TestGetWorkoutsWithFilters:
sport_1_cycling: Sport,
seven_workouts_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts?ave_speed_from=5&ave_speed_to=10',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -705,19 +562,11 @@ class TestGetWorkoutsWithFilters:
) -> None:
workout_cycling_user_1.max_speed = 25
workout_running_user_1.max_speed = 11
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts?max_speed_from=10&max_speed_to=20',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -738,19 +587,11 @@ class TestGetWorkoutsWithFilters:
sport_2_running: Sport,
workout_running_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts?sport_id=2',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -763,7 +604,7 @@ class TestGetWorkoutsWithFilters:
)
class TestGetWorkoutsWithFiltersAndPagination:
class TestGetWorkoutsWithFiltersAndPagination(ApiTestCaseMixin):
def test_it_gets_page_2_with_date_filter(
self,
app: Flask,
@ -771,19 +612,11 @@ class TestGetWorkoutsWithFiltersAndPagination:
sport_1_cycling: Sport,
seven_workouts_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts?from=2017-01-01&page=2',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -806,19 +639,11 @@ class TestGetWorkoutsWithFiltersAndPagination:
sport_1_cycling: Sport,
seven_workouts_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
'/api/workouts?from=2017-01-01&page=2&order=asc',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -835,7 +660,7 @@ class TestGetWorkoutsWithFiltersAndPagination:
)
class TestGetWorkout:
class TestGetWorkout(ApiTestCaseMixin):
def test_it_gets_an_workout(
self,
app: Flask,
@ -843,19 +668,11 @@ class TestGetWorkout:
sport_1_cycling: Sport,
workout_cycling_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/workouts/{workout_cycling_user_1.short_id}',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -880,19 +697,11 @@ class TestGetWorkout:
sport_1_cycling: Sport,
workout_cycling_user_2: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/workouts/{workout_cycling_user_2.short_id}',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -903,19 +712,11 @@ class TestGetWorkout:
def test_it_returns_404_if_workout_does_not_exist(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/workouts/{get_random_short_id()}',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -927,19 +728,11 @@ class TestGetWorkout:
self, app: Flask, user_1: User
) -> None:
random_short_id = get_random_short_id()
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/workouts/{random_short_id}/gpx',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -952,19 +745,11 @@ class TestGetWorkout:
self, app: Flask, user_1: User
) -> None:
random_short_id = get_random_short_id()
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/workouts/{random_short_id}/chart_data',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -981,19 +766,11 @@ class TestGetWorkout:
workout_cycling_user_1: Workout,
) -> None:
workout_short_id = workout_cycling_user_1.short_id
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/workouts/{workout_short_id}/gpx',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1012,19 +789,11 @@ class TestGetWorkout:
workout_cycling_user_1: Workout,
) -> None:
workout_short_id = workout_cycling_user_1.short_id
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/workouts/{workout_short_id}/chart_data',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1043,19 +812,11 @@ class TestGetWorkout:
workout_cycling_user_1: Workout,
) -> None:
workout_cycling_user_1.gpx = "some path"
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/workouts/{workout_cycling_user_1.short_id}/gpx',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1075,19 +836,11 @@ class TestGetWorkout:
workout_cycling_user_1: Workout,
) -> None:
workout_cycling_user_1.gpx = 'some path'
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/workouts/{workout_cycling_user_1.short_id}/chart_data',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1102,18 +855,10 @@ class TestGetWorkout:
def test_it_returns_404_if_workout_has_no_map(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.get(
f'/api/workouts/map/{uuid4().hex}',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())

View File

@ -10,6 +10,8 @@ from fittrackee.users.models import User
from fittrackee.workouts.models import Sport, Workout
from fittrackee.workouts.utils_id import decode_short_id
from ..api_test_case import ApiTestCaseMixin
def assert_workout_data_with_gpx(data: Dict) -> None:
assert 'creation_date' in data['data']['workouts'][0]
@ -201,16 +203,11 @@ def assert_workout_data_wo_gpx(data: Dict) -> None:
assert records[3]['value'] == 10.0
class TestPostWorkoutWithGpx:
class TestPostWorkoutWithGpx(ApiTestCaseMixin):
def test_it_adds_an_workout_with_gpx_file(
self, app: Flask, user_1: User, sport_1_cycling: Sport, gpx_file: str
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts',
@ -220,8 +217,7 @@ class TestPostWorkoutWithGpx:
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
@ -239,12 +235,7 @@ class TestPostWorkoutWithGpx:
sport_1_cycling: Sport,
gpx_file_wo_name: str,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts',
@ -254,8 +245,7 @@ class TestPostWorkoutWithGpx:
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
@ -277,12 +267,7 @@ class TestPostWorkoutWithGpx:
gpx_file_wo_name: str,
) -> None:
user_1.timezone = 'Europe/Paris'
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts',
@ -292,8 +277,7 @@ class TestPostWorkoutWithGpx:
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
@ -310,12 +294,7 @@ class TestPostWorkoutWithGpx:
def test_it_adds_get_an_workout_with_gpx_notes(
self, app: Flask, user_1: User, sport_1_cycling: Sport, gpx_file: str
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts',
@ -325,8 +304,7 @@ class TestPostWorkoutWithGpx:
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
data = json.loads(response.data.decode())
@ -344,12 +322,7 @@ class TestPostWorkoutWithGpx:
sport_1_cycling: Sport,
gpx_file_wo_track: str,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts',
@ -359,8 +332,7 @@ class TestPostWorkoutWithGpx:
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
@ -377,12 +349,7 @@ class TestPostWorkoutWithGpx:
sport_1_cycling: Sport,
gpx_file_invalid_xml: str,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts',
@ -395,8 +362,7 @@ class TestPostWorkoutWithGpx:
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
@ -409,12 +375,7 @@ class TestPostWorkoutWithGpx:
def test_it_returns_400_if_workout_gpx_has_invalid_extension(
self, app: Flask, user_1: User, sport_1_cycling: Sport, gpx_file: str
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts',
@ -424,8 +385,7 @@ class TestPostWorkoutWithGpx:
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
@ -437,12 +397,7 @@ class TestPostWorkoutWithGpx:
def test_it_returns_400_if_sport_id_is_not_provided(
self, app: Flask, user_1: User, sport_1_cycling: Sport, gpx_file: str
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts',
@ -451,8 +406,7 @@ class TestPostWorkoutWithGpx:
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
@ -464,12 +418,7 @@ class TestPostWorkoutWithGpx:
def test_it_returns_500_if_sport_id_does_not_exists(
self, app: Flask, user_1: User, sport_1_cycling: Sport, gpx_file: str
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts',
@ -479,8 +428,7 @@ class TestPostWorkoutWithGpx:
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
@ -492,20 +440,14 @@ class TestPostWorkoutWithGpx:
def test_returns_400_if_no_gpx_file_is_provided(
self, app: Flask, user_1: User, sport_1_cycling: Sport
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts',
data=dict(data='{}'),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
@ -514,17 +456,43 @@ class TestPostWorkoutWithGpx:
assert data['status'] == 'fail'
assert data['message'] == 'No file part.'
def test_it_returns_error_if_file_size_exceeds_limit(
self,
app_with_max_file_size: Flask,
user_1: User,
sport_1_cycling: Sport,
gpx_file: str,
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app_with_max_file_size
)
class TestPostWorkoutWithoutGpx:
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',
Authorization=f'Bearer {auth_token}',
),
)
data = json.loads(response.data.decode())
assert response.status_code == 413
assert 'fail' in data['status']
assert (
'Error during workout upload, file size (3.6KB) exceeds 1.0KB.'
in data['message']
)
assert 'data' not in data
class TestPostWorkoutWithoutGpx(ApiTestCaseMixin):
def test_it_adds_an_workout_without_gpx(
self, app: Flask, user_1: User, sport_1_cycling: Sport
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts/no_gpx',
@ -537,10 +505,7 @@ class TestPostWorkoutWithoutGpx:
distance=10,
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -552,21 +517,13 @@ class TestPostWorkoutWithoutGpx:
def test_it_returns_400_if_workout_date_is_missing(
self, app: Flask, user_1: User, sport_1_cycling: Sport
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts/no_gpx',
content_type='application/json',
data=json.dumps(dict(sport_id=1, duration=3600, distance=10)),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -577,12 +534,7 @@ class TestPostWorkoutWithoutGpx:
def test_it_returns_500_if_workout_format_is_invalid(
self, app: Flask, user_1: User, sport_1_cycling: Sport
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts/no_gpx',
@ -595,10 +547,7 @@ class TestPostWorkoutWithoutGpx:
distance=10,
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -613,12 +562,7 @@ class TestPostWorkoutWithoutGpx:
sport_1_cycling: Sport,
sport_2_running: Sport,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts/no_gpx',
@ -632,10 +576,7 @@ class TestPostWorkoutWithoutGpx:
title='Workout test',
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -666,21 +607,14 @@ class TestPostWorkoutWithoutGpx:
assert len(data['data']['workouts'][0]['records']) == 0
class TestPostWorkoutWithZipArchive:
class TestPostWorkoutWithZipArchive(ApiTestCaseMixin):
def test_it_adds_workouts_with_zip_archive(
self, app: Flask, user_1: User, sport_1_cycling: Sport
) -> None:
file_path = os.path.join(app.root_path, 'tests/files/gpx_test.zip')
# 'gpx_test.zip' contains 3 gpx files (same data) and 1 non-gpx file
with open(file_path, 'rb') as zip_file:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='test@test.com', password='12345678')
),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts',
@ -689,8 +623,7 @@ class TestPostWorkoutWithZipArchive:
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
@ -710,14 +643,7 @@ class TestPostWorkoutWithZipArchive:
# 'gpx_test_folder.zip' contains 3 gpx files (same data) and 1 non-gpx
# file in a folder
with open(file_path, 'rb') as zip_file:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='test@test.com', password='12345678')
),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts',
@ -727,8 +653,7 @@ class TestPostWorkoutWithZipArchive:
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
@ -745,14 +670,7 @@ class TestPostWorkoutWithZipArchive:
)
# 'gpx_test_incorrect.zip' contains 2 gpx files, one is incorrect
with open(file_path, 'rb') as zip_file:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='test@test.com', password='12345678')
),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts',
@ -762,8 +680,7 @@ class TestPostWorkoutWithZipArchive:
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
@ -784,13 +701,8 @@ class TestPostWorkoutWithZipArchive:
)
# 'gpx_test.zip' contains 3 gpx files (same data) and 1 non-gpx file
with open(file_path, 'rb') as zip_file:
client = app_with_max_workouts.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(
dict(email='test@test.com', password='12345678')
),
content_type='application/json',
client, auth_token = self.get_test_client_and_auth_token(
app_with_max_workouts
)
client.post(
@ -800,33 +712,57 @@ class TestPostWorkoutWithZipArchive:
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
response = client.get(
'/api/workouts',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
assert len(data['data']['workouts']) == 2
class TestPostAndGetWorkoutWithGpx:
@staticmethod
def workout_assertion(
app: Flask, gpx_file: str, with_segments: bool
def test_it_returns_error_if_archive_size_exceeds_limit(
self,
app_with_max_zip_file_size: Flask,
user_1: User,
sport_1_cycling: Sport,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
file_path = os.path.join(
app_with_max_zip_file_size.root_path, 'tests/files/gpx_test.zip'
)
# 'gpx_test.zip' contains 3 gpx files (same data) and 1 non-gpx file
with open(file_path, 'rb') as zip_file:
client, auth_token = self.get_test_client_and_auth_token(
app_with_max_zip_file_size
)
response = client.post(
'/api/workouts',
data=dict(
file=(zip_file, 'gpx_test.zip'), data='{"sport_id": 1}'
),
headers=dict(
content_type='multipart/form-data',
Authorization=f'Bearer {auth_token}',
),
)
data = json.loads(response.data.decode())
assert response.status_code == 413
assert 'fail' in data['status']
assert (
'Error during workout upload, file size (2.5KB) exceeds 1.0KB.'
in data['message']
)
assert 'data' not in data
class TestPostAndGetWorkoutWithGpx(ApiTestCaseMixin):
def workout_assertion(
self, app: Flask, gpx_file: str, with_segments: bool
) -> None:
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts',
data=dict(
@ -835,8 +771,7 @@ class TestPostAndGetWorkoutWithGpx:
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
@ -854,10 +789,7 @@ class TestPostAndGetWorkoutWithGpx:
response = client.get(
f'/api/workouts/{workout_short_id}/gpx',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -868,10 +800,7 @@ class TestPostAndGetWorkoutWithGpx:
response = client.get(
f'/api/workouts/{workout_short_id}/gpx/segment/1',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -882,10 +811,7 @@ class TestPostAndGetWorkoutWithGpx:
response = client.get(
f'/api/workouts/map/{map_id}',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
assert response.status_code == 200
@ -901,10 +827,7 @@ class TestPostAndGetWorkoutWithGpx:
response = client.get(
f'/api/workouts/map/{map_id}',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -932,12 +855,7 @@ class TestPostAndGetWorkoutWithGpx:
def test_it_gets_chart_data_for_an_workout_created_with_gpx(
self, app: Flask, user_1: User, sport_1_cycling: Sport, gpx_file: str
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts',
@ -947,18 +865,14 @@ class TestPostAndGetWorkoutWithGpx:
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
data = json.loads(response.data.decode())
workout_short_id = data['data']['workouts'][0]['id']
response = client.get(
f'/api/workouts/{workout_short_id}/chart_data',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -970,12 +884,7 @@ class TestPostAndGetWorkoutWithGpx:
def test_it_gets_segment_chart_data_for_an_workout_created_with_gpx(
self, app: Flask, user_1: User, sport_1_cycling: Sport, gpx_file: str
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts',
@ -985,18 +894,14 @@ class TestPostAndGetWorkoutWithGpx:
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
data = json.loads(response.data.decode())
workout_short_id = data['data']['workouts'][0]['id']
response = client.get(
f'/api/workouts/{workout_short_id}/chart_data/segment/1',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1013,12 +918,7 @@ class TestPostAndGetWorkoutWithGpx:
sport_1_cycling: Sport,
gpx_file: str,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts',
data=dict(
@ -1027,8 +927,7 @@ class TestPostAndGetWorkoutWithGpx:
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
data = json.loads(response.data.decode())
@ -1055,12 +954,7 @@ class TestPostAndGetWorkoutWithGpx:
def test_it_returns_500_on_invalid_segment_id(
self, app: Flask, user_1: User, sport_1_cycling: Sport, gpx_file: str
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts',
@ -1070,18 +964,14 @@ class TestPostAndGetWorkoutWithGpx:
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
data = json.loads(response.data.decode())
workout_short_id = data['data']['workouts'][0]['id']
response = client.get(
f'/api/workouts/{workout_short_id}/chart_data/segment/0',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1093,12 +983,7 @@ class TestPostAndGetWorkoutWithGpx:
def test_it_returns_404_if_segment_id_does_not_exist(
self, app: Flask, user_1: User, sport_1_cycling: Sport, gpx_file: str
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts',
@ -1108,18 +993,14 @@ class TestPostAndGetWorkoutWithGpx:
),
headers=dict(
content_type='multipart/form-data',
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token'],
Authorization=f'Bearer {auth_token}',
),
)
data = json.loads(response.data.decode())
workout_short_id = data['data']['workouts'][0]['id']
response = client.get(
f'/api/workouts/{workout_short_id}/chart_data/segment/999999',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1129,16 +1010,11 @@ class TestPostAndGetWorkoutWithGpx:
assert 'data' not in data
class TestPostAndGetWorkoutWithoutGpx:
class TestPostAndGetWorkoutWithoutGpx(ApiTestCaseMixin):
def test_it_add_and_gets_an_workout_wo_gpx(
self, app: Flask, user_1: User, sport_1_cycling: Sport
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts/no_gpx',
@ -1151,19 +1027,13 @@ class TestPostAndGetWorkoutWithoutGpx:
distance=10,
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
workout_short_id = data['data']['workouts'][0]['id']
response = client.get(
f'/api/workouts/{workout_short_id}',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1175,12 +1045,7 @@ class TestPostAndGetWorkoutWithoutGpx:
def test_it_adds_and_gets_an_workout_wo_gpx_notes(
self, app: Flask, user_1: User, sport_1_cycling: Sport
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts/no_gpx',
@ -1194,19 +1059,13 @@ class TestPostAndGetWorkoutWithoutGpx:
notes="new test with notes",
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
workout_short_id = data['data']['workouts'][0]['id']
response = client.get(
f'/api/workouts/{workout_short_id}',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1216,17 +1075,12 @@ class TestPostAndGetWorkoutWithoutGpx:
assert 'new test with notes' == data['data']['workouts'][0]['notes']
class TestPostAndGetWorkoutUsingTimezones:
class TestPostAndGetWorkoutUsingTimezones(ApiTestCaseMixin):
def test_it_add_and_gets_an_workout_wo_gpx_with_timezone(
self, app: Flask, user_1: User, sport_1_cycling: Sport
) -> None:
user_1.timezone = 'Europe/Paris'
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.post(
'/api/workouts/no_gpx',
@ -1239,19 +1093,13 @@ class TestPostAndGetWorkoutUsingTimezones:
distance=10,
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
workout_short_id = data['data']['workouts'][0]['id']
response = client.get(
f'/api/workouts/{workout_short_id}',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1270,12 +1118,7 @@ class TestPostAndGetWorkoutUsingTimezones:
def test_it_adds_and_gets_workouts_date_filter_with_timezone_new_york(
self, app: Flask, user_1_full: User, sport_1_cycling: Sport
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
client.post(
'/api/workouts/no_gpx',
@ -1288,17 +1131,11 @@ class TestPostAndGetWorkoutUsingTimezones:
distance=10,
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
response = client.get(
'/api/workouts?from=2018-01-01&to=2018-01-31',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -1321,12 +1158,7 @@ class TestPostAndGetWorkoutUsingTimezones:
sport_1_cycling: Sport,
workout_cycling_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
client.post(
'/api/workouts/no_gpx',
@ -1339,10 +1171,7 @@ class TestPostAndGetWorkoutUsingTimezones:
distance=10,
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
client.post(
'/api/workouts/no_gpx',
@ -1355,10 +1184,7 @@ class TestPostAndGetWorkoutUsingTimezones:
distance=10,
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
workout_cycling_user_1.workout_date = datetime.strptime(
@ -1377,17 +1203,11 @@ class TestPostAndGetWorkoutUsingTimezones:
distance=10,
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
response = client.get(
'/api/workouts?from=2018-01-01&to=2018-01-31',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())

View File

@ -7,6 +7,7 @@ from fittrackee.users.models import User
from fittrackee.workouts.models import Sport, Workout
from fittrackee.workouts.utils_id import decode_short_id
from ..api_test_case import ApiTestCaseMixin
from .utils import get_random_short_id, post_an_workout
@ -53,7 +54,7 @@ def assert_workout_data_with_gpx(data: Dict, sport_id: int) -> None:
assert records[3]['value'] == 4.61
class TestEditWorkoutWithGpx:
class TestEditWorkoutWithGpx(ApiTestCaseMixin):
def test_it_updates_title_for_an_workout_with_gpx(
self,
app: Flask,
@ -203,7 +204,7 @@ class TestEditWorkoutWithGpx:
)
class TestEditWorkoutWithoutGpx:
class TestEditWorkoutWithoutGpx(ApiTestCaseMixin):
def test_it_updates_an_workout_wo_gpx(
self,
app: Flask,
@ -213,12 +214,7 @@ class TestEditWorkoutWithoutGpx:
workout_cycling_user_1: Workout,
) -> None:
workout_short_id = workout_cycling_user_1.short_id
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.patch(
f'/api/workouts/{workout_short_id}',
@ -232,10 +228,7 @@ class TestEditWorkoutWithoutGpx:
title='Workout test',
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -298,21 +291,13 @@ class TestEditWorkoutWithoutGpx:
workout_cycling_user_1: Workout,
) -> None:
workout_short_id = workout_cycling_user_1.short_id
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.patch(
f'/api/workouts/{workout_short_id}',
content_type='application/json',
data=json.dumps(dict(notes='test notes')),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -374,12 +359,7 @@ class TestEditWorkoutWithoutGpx:
sport_1_cycling: Sport,
workout_cycling_user_2: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.patch(
f'/api/workouts/{workout_cycling_user_2.short_id}',
@ -393,10 +373,7 @@ class TestEditWorkoutWithoutGpx:
title='Workout test',
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -413,12 +390,7 @@ class TestEditWorkoutWithoutGpx:
workout_cycling_user_1: Workout,
) -> None:
workout_short_id = workout_cycling_user_1.short_id
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.patch(
f'/api/workouts/{workout_short_id}',
@ -432,10 +404,7 @@ class TestEditWorkoutWithoutGpx:
title='Workout test',
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -494,21 +463,13 @@ class TestEditWorkoutWithoutGpx:
workout_cycling_user_1: Workout,
) -> None:
workout_short_id = workout_cycling_user_1.short_id
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.patch(
f'/api/workouts/{workout_short_id}',
content_type='application/json',
data=json.dumps(dict(sport_id=2, distance=20)),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -565,21 +526,13 @@ class TestEditWorkoutWithoutGpx:
sport_1_cycling: Sport,
workout_cycling_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.patch(
f'/api/workouts/{workout_cycling_user_1.short_id}',
content_type='application/json',
data=json.dumps(dict()),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -594,12 +547,7 @@ class TestEditWorkoutWithoutGpx:
sport_1_cycling: Sport,
workout_cycling_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.patch(
f'/api/workouts/{workout_cycling_user_1.short_id}',
content_type='application/json',
@ -611,10 +559,7 @@ class TestEditWorkoutWithoutGpx:
distance=10,
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
@ -629,12 +574,7 @@ class TestEditWorkoutWithoutGpx:
def test_it_returns_404_if_edited_workout_does_not_exists(
self, app: Flask, user_1: User, sport_1_cycling: Sport
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.patch(
f'/api/workouts/{get_random_short_id()}',
content_type='application/json',
@ -646,10 +586,7 @@ class TestEditWorkoutWithoutGpx:
distance=10,
)
),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())

View File

@ -7,6 +7,7 @@ from fittrackee.users.models import User
from fittrackee.workouts.models import Sport, Workout
from fittrackee.workouts.utils import get_absolute_file_path
from ..api_test_case import ApiTestCaseMixin
from .utils import get_random_short_id, post_an_workout
@ -15,7 +16,7 @@ def get_gpx_filepath(workout_id: int) -> str:
return workout.gpx
class TestDeleteWorkoutWithGpx:
class TestDeleteWorkoutWithGpx(ApiTestCaseMixin):
def test_it_deletes_an_workout_with_gpx(
self, app: Flask, user_1: User, sport_1_cycling: Sport, gpx_file: str
) -> None:
@ -62,18 +63,10 @@ class TestDeleteWorkoutWithGpx:
def test_it_returns_404_if_workout_does_not_exist(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.delete(
f'/api/workouts/{get_random_short_id()}',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
assert response.status_code == 404
@ -103,7 +96,7 @@ class TestDeleteWorkoutWithGpx:
)
class TestDeleteWorkoutWithoutGpx:
class TestDeleteWorkoutWithoutGpx(ApiTestCaseMixin):
def test_it_deletes_an_workout_wo_gpx(
self,
app: Flask,
@ -111,18 +104,10 @@ class TestDeleteWorkoutWithoutGpx:
sport_1_cycling: Sport,
workout_cycling_user_1: Workout,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.delete(
f'/api/workouts/{workout_cycling_user_1.short_id}',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
headers=dict(Authorization=f'Bearer {auth_token}'),
)
assert response.status_code == 204

View File

@ -18,17 +18,12 @@ from fittrackee.responses import (
handle_error_and_return_response,
)
from fittrackee.tasks import reset_password_email
from fittrackee.utils import get_readable_duration, verify_extension_and_size
from fittrackee.workouts.utils_files import get_absolute_file_path
from .decorators import authenticate
from .models import User
from .utils import (
check_passwords,
display_readable_file_size,
get_readable_duration,
register_controls,
verify_extension_and_size,
)
from .utils import check_passwords, register_controls
from .utils_token import decode_user_token
auth_blueprint = Blueprint('auth', __name__)
@ -524,10 +519,10 @@ def edit_picture(auth_user_id: int) -> Union[Dict, HttpResponse]:
response_object = verify_extension_and_size('picture', request)
except RequestEntityTooLarge as e:
appLog.error(e)
max_file_size = current_app.config['MAX_CONTENT_LENGTH']
return PayloadTooLargeErrorResponse(
'Error during picture update, file size exceeds '
f'{display_readable_file_size(max_file_size)}.'
file_type='picture',
file_size=request.content_length,
max_size=current_app.config['MAX_CONTENT_LENGTH'],
)
if response_object:
return response_object

View File

@ -1,15 +1,11 @@
import re
from datetime import timedelta
from typing import Optional, Tuple, Union
from typing import Optional, Tuple
import humanize
from flask import Request, current_app
from flask import Request
from fittrackee.responses import (
ForbiddenErrorResponse,
HttpResponse,
InvalidPayloadErrorResponse,
PayloadTooLargeErrorResponse,
UnauthorizedErrorResponse,
)
@ -64,49 +60,6 @@ def register_controls(
return ret
def verify_extension_and_size(
file_type: str, req: Request
) -> Optional[HttpResponse]:
"""
Return error Response if file is invalid
"""
if 'file' not in req.files:
return InvalidPayloadErrorResponse('No file part.', 'fail')
file = req.files['file']
if file.filename == '':
return InvalidPayloadErrorResponse('No selected file.', 'fail')
allowed_extensions = (
'WORKOUT_ALLOWED_EXTENSIONS'
if file_type == 'workout'
else 'PICTURE_ALLOWED_EXTENSIONS'
)
file_extension = (
file.filename.rsplit('.', 1)[1].lower()
if '.' in file.filename
else None
)
max_file_size = current_app.config['max_single_file_size']
if not (
file_extension
and file_extension in current_app.config[allowed_extensions]
):
return InvalidPayloadErrorResponse(
'File extension not allowed.', 'fail'
)
if file_extension != 'zip' and req.content_length > max_file_size:
return PayloadTooLargeErrorResponse(
'Error during picture update, file size exceeds '
f'{display_readable_file_size(max_file_size)}.'
)
return None
def verify_user(
current_request: Request, verify_admin: bool
) -> Tuple[Optional[HttpResponse], Optional[int]]:
@ -139,35 +92,3 @@ def can_view_workout(
if auth_user_id != workout_user_id:
return ForbiddenErrorResponse()
return None
def display_readable_file_size(size_in_bytes: Union[float, int]) -> str:
"""
Return readable file size from size in bytes
"""
if size_in_bytes == 0:
return '0 bytes'
if size_in_bytes == 1:
return '1 byte'
for unit in [' bytes', 'KB', 'MB', 'GB', 'TB']:
if abs(size_in_bytes) < 1024.0:
return f'{size_in_bytes:3.1f}{unit}'
size_in_bytes /= 1024.0
return f'{size_in_bytes} bytes'
def get_readable_duration(duration: int, locale: Optional[str] = None) -> str:
"""
Return readable and localized duration from duration in seconds
"""
if locale is None:
locale = 'en'
if locale != 'en':
try:
_t = humanize.i18n.activate(locale) # noqa
except FileNotFoundError:
locale = 'en'
readable_duration = humanize.naturaldelta(timedelta(seconds=duration))
if locale != 'en':
humanize.i18n.deactivate()
return readable_duration

76
fittrackee/utils.py Normal file
View File

@ -0,0 +1,76 @@
from datetime import timedelta
from typing import Optional
import humanize
from flask import Request, current_app
from .responses import (
HttpResponse,
InvalidPayloadErrorResponse,
PayloadTooLargeErrorResponse,
)
def verify_extension_and_size(
file_type: str, req: Request
) -> Optional[HttpResponse]:
"""
Return error Response if file is invalid
"""
if 'file' not in req.files:
return InvalidPayloadErrorResponse('No file part.', 'fail')
file = req.files['file']
if file.filename == '':
return InvalidPayloadErrorResponse('No selected file.', 'fail')
allowed_extensions = (
'WORKOUT_ALLOWED_EXTENSIONS'
if file_type == 'workout'
else 'PICTURE_ALLOWED_EXTENSIONS'
)
file_extension = (
file.filename.rsplit('.', 1)[1].lower()
if '.' in file.filename
else None
)
max_file_size = current_app.config['max_single_file_size']
if not (
file_extension
and file_extension in current_app.config[allowed_extensions]
):
return InvalidPayloadErrorResponse(
'File extension not allowed.', 'fail'
)
if (
file_extension != 'zip'
and req.content_length is not None
and req.content_length > max_file_size
):
return PayloadTooLargeErrorResponse(
file_type=file_type,
file_size=req.content_length,
max_size=max_file_size,
)
return None
def get_readable_duration(duration: int, locale: Optional[str] = None) -> str:
"""
Return readable and localized duration from duration in seconds
"""
if locale is None:
locale = 'en'
if locale != 'en':
try:
_t = humanize.i18n.activate(locale) # noqa
except FileNotFoundError:
locale = 'en'
readable_duration = humanize.naturaldelta(timedelta(seconds=duration))
if locale != 'en':
humanize.i18n.deactivate()
return readable_duration

View File

@ -7,6 +7,7 @@ from typing import Any, Dict, List, Optional, Tuple, Union
import requests
from flask import Blueprint, Response, current_app, request, send_file
from sqlalchemy import exc
from werkzeug.exceptions import RequestEntityTooLarge
from fittrackee import appLog, db
from fittrackee.responses import (
@ -16,14 +17,13 @@ from fittrackee.responses import (
InternalServerErrorResponse,
InvalidPayloadErrorResponse,
NotFoundErrorResponse,
PayloadTooLargeErrorResponse,
handle_error_and_return_response,
)
from fittrackee.users.decorators import authenticate
from fittrackee.users.utils import (
User,
can_view_workout,
verify_extension_and_size,
)
from fittrackee.users.models import User
from fittrackee.users.utils import can_view_workout
from fittrackee.utils import verify_extension_and_size
from .models import Workout
from .utils import (
@ -880,7 +880,15 @@ def post_workout(auth_user_id: int) -> Union[Tuple[Dict, int], HttpResponse]:
:statuscode 500:
"""
error_response = verify_extension_and_size('workout', request)
try:
error_response = verify_extension_and_size('workout', request)
except RequestEntityTooLarge as e:
appLog.error(e)
return PayloadTooLargeErrorResponse(
file_type='workout',
file_size=request.content_length,
max_size=current_app.config['MAX_CONTENT_LENGTH'],
)
if error_response:
return error_response

View File

@ -1,5 +1,7 @@
import FitTrackeeGenericApi from '../fitTrackeeApi'
import { setError } from './index'
import { history } from '../index'
import { generateIds } from '../utils'
import { emptyMessages, setError } from './index'
export const setAppConfig = data => ({
type: 'SET_APP_CONFIG',
@ -11,6 +13,8 @@ export const setAppStats = data => ({
data,
})
const SetAppErrors = messages => ({ type: 'APP_ERRORS', messages })
export const getAppData = target => dispatch =>
FitTrackeeGenericApi.getData(target)
.then(ret => {
@ -26,13 +30,18 @@ export const getAppData = target => dispatch =>
})
.catch(error => dispatch(setError(`application|${error}`)))
export const updateAppConfig = formData => dispatch =>
export const updateAppConfig = formData => dispatch => {
dispatch(emptyMessages())
FitTrackeeGenericApi.updateData('config', formData)
.then(ret => {
if (ret.status === 'success') {
dispatch(setAppConfig(ret.data))
history.push('/admin/application')
} else if (Array.isArray(ret.message)) {
dispatch(SetAppErrors(generateIds(ret.message)))
} else {
dispatch(setError(`application|${ret.message}`))
dispatch(setError(ret.message))
}
})
.catch(error => dispatch(setError(`application|${error}`)))
}

View File

@ -3,11 +3,16 @@ import i18next from 'i18next'
import FitTrackeeApi from '../fitTrackeeApi/index'
import { history } from '../index'
export const emptyMessages = () => ({
type: 'CLEAN_ALL_MESSAGES',
})
export const setData = (target, data) => ({
type: 'SET_DATA',
data,
target,
})
export const setPaginatedData = (target, data, pagination) => ({
type: 'SET_PAGINATED_DATA',
data,
@ -51,7 +56,7 @@ export const getOrUpdateData = (
dispatch(setLoading(false))
return dispatch(setError(`${target}|Incorrect id`))
}
dispatch(setError(''))
dispatch(emptyMessages())
return FitTrackeeApi[action](target, data)
.then(ret => {
if (ret.status === 'success') {

View File

@ -2,7 +2,7 @@ import React from 'react'
import { connect } from 'react-redux'
import Message from '../Common/Message'
import { updateAppConfig } from '../../actions/application'
import { getAppData, updateAppConfig } from '../../actions/application'
import { history } from '../../index'
import { getFileSizeInMB } from '../../utils'
@ -11,7 +11,6 @@ class AdminApplication extends React.Component {
super(props, context)
this.state = {
formData: {},
isInEdition: false,
}
}
@ -44,18 +43,21 @@ class AdminApplication extends React.Component {
this.setState(formData)
}
toggleInEdition(e) {
e.preventDefault()
const { isInEdition } = this.state
this.setState({ isInEdition: !isInEdition })
}
render() {
const { message, onHandleConfigFormSubmit, t } = this.props
const { formData, isInEdition } = this.state
const {
isInEdition,
loadAppConfig,
message,
messages,
onHandleConfigFormSubmit,
t,
} = this.props
const { formData } = this.state
return (
<div>
{message && <Message message={message} t={t} />}
{(message || messages) && (
<Message message={message} messages={messages} t={t} />
)}
{Object.keys(formData).length > 0 && (
<div className="row">
<div className="col-md-12">
@ -71,7 +73,7 @@ class AdminApplication extends React.Component {
isInEdition ? '' : 'form-disabled'
}`}
onSubmit={e => {
this.toggleInEdition(e)
e.preventDefault()
onHandleConfigFormSubmit(formData)
}}
>
@ -169,7 +171,11 @@ class AdminApplication extends React.Component {
<input
type="submit"
className="btn btn-secondary"
onClick={e => this.toggleInEdition(e)}
onClick={e => {
e.preventDefault()
loadAppConfig()
history.push('/admin/application')
}}
value={t('common:Cancel')}
/>
</>
@ -179,7 +185,8 @@ class AdminApplication extends React.Component {
type="submit"
className="btn btn-primary"
onClick={e => {
this.toggleInEdition(e)
e.preventDefault()
history.push('/admin/application/edit')
}}
value={t('common:Edit')}
/>
@ -205,8 +212,12 @@ class AdminApplication extends React.Component {
export default connect(
state => ({
message: state.message,
messages: state.messages,
}),
dispatch => ({
loadAppConfig: () => {
dispatch(getAppData('config'))
},
onHandleConfigFormSubmit: formData => {
const data = Object.assign({}, formData)
data.max_single_file_size *= 1048576

View File

@ -28,7 +28,20 @@ function Admin(props) {
<Route
exact
path="/admin/application"
render={() => <AdminApplication appConfig={appConfig} t={t} />}
render={() => (
<AdminApplication
appConfig={appConfig}
t={t}
isInEdition={false}
/>
)}
/>
<Route
exact
path="/admin/application/edit"
render={() => (
<AdminApplication appConfig={appConfig} t={t} isInEdition />
)}
/>
<Route
exact

View File

@ -228,7 +228,7 @@ label {
}
.error-message {
margin-top: 10px;
margin: 10px 0;
}
.fa-as-link {

View File

@ -14,15 +14,19 @@ export default class Message extends React.PureComponent {
return (
<div className="error-message">
{singleMessage !== '' && <code>{singleMessage}</code>}
{messages && messages.length > 0 && (
<code>
<ul>
{messages.map(msg => (
<li key={msg.id}>{t(`messages:${msg.value}`)}</li>
))}
</ul>
</code>
)}
{messages &&
messages.length > 0 &&
(messages.length === 1 ? (
<code>{messages[0].value}</code>
) : (
<code>
<ul>
{messages.map(msg => (
<li key={msg.id}>{t(`messages:${msg.value}`)}</li>
))}
</ul>
</code>
))}
</div>
)
}

View File

@ -2,7 +2,7 @@
"3 to 12 characters required for username.": "3 to 12 characters required for username.",
"8 characters required for password.": "8 characters required for password.",
"An error occurred. Please contact the administrator.": "An error occurred. Please contact the administrator.",
"workouts": "workouts",
"application": "application",
"Error during picture deletion.": "Error during picture deletion.",
"Error during picture update.": "Error during picture update.",
"Error during picture update, file size exceeds max size.": "Error during picture update, file size exceeds max size.",
@ -14,6 +14,10 @@
"Invalid credentials.": "Invalid credentials.",
"Invalid payload.": "Invalid payload.",
"Invalid token. Please log in again.": "Invalid token. Please log in again.",
"Max. files in a zip archive must be greater than 0": "Max. files in a zip archive must be greater than 0",
"Max. size of uploaded files must be greater than 0": "Max. size of uploaded files must be greater than 0",
"Max. size of zip archive must be equal or greater than max. size of uploaded files": "Max. size of zip archive must be equal or greater than max. size of uploaded files",
"Max. size of zip archive must be greater than 0": "Max. size of zip archive must be greater than 0",
"No file part.": "No file part.",
"No picture.": "No picture.",
"No selected file.": "No selected file.",
@ -30,6 +34,7 @@
"statistics": "statistiques",
"User does not exist.": "User does not exist.",
"Valid email must be provided.\n": "Valid email must be provided.",
"workouts": "workouts",
"You can not delete your account, no other user has admin rights.": "You can not delete your account, no other user has admin rights.",
"You do not have permissions.": "You do not have permissions."
}

View File

@ -2,7 +2,7 @@
"3 to 12 characters required for username.": "3 à 12 caractères requis pour le nom.",
"8 characters required for password.": "8 caractères minimum pour le mot de passe.",
"An error occurred. Please contact the administrator.": "Une erreur s'est produite. Merci de contacter l'administrateur.",
"workouts": "séances",
"application": "application",
"Error during picture deletion.": "Erreur lors de la suppression de l'image.",
"Error during picture update.": "Erreur lors de la mise à jour de l'image.",
"Error during picture update, file size exceeds max size.": "Erreur lors de la mise à jour de l'image, la taille du ficher dépasse la taille maximum autorisée",
@ -14,6 +14,10 @@
"Invalid credentials.": "Identifiants invalides.",
"Invalid payload.": "Données incorrectes.",
"Invalid token. Please log in again.": "Jeton invalide. Merci de vous reconnecter.",
"Max. files in a zip archive must be greater than 0": "Le nombre max. de fichiers dans une archive doit être supérieur à 0",
"Max. size of uploaded files must be greater than 0": "La taille max. des fichiers doit être supérieure à 0",
"Max. size of zip archive must be equal or greater than max. size of uploaded files": "La taille max. d'une archive doit être supérieure ou égale à la taille max. d'un fichier",
"Max. size of zip archive must be greater than 0": "La taille max. d'une archive doit être supérieure à 0",
"No file part.": "Pas de fichier fourni.",
"No picture.": "Pas d'image.",
"No selected file.": "Pas de fichier sélectionné.",
@ -30,6 +34,7 @@
"statistics": "statistics",
"User does not exist.": "L'utilisateur n'existe pas.",
"Valid email must be provided.\n": "L'email fourni n'est pas valide.",
"workouts": "séances",
"You can not delete your account, no other user has admin rights.": "Vous ne pouvez pas supprimer votre compte, aucun autre utilisateur n'a des droits d'administration.",
"You do not have permissions.": "Vous n'avez pas les permissions nécessaires."
}

View File

@ -108,8 +108,10 @@ const message = (state = initial.message, action) => {
case 'PICTURE_ERROR':
case 'SET_ERROR':
return action.message
case 'CLEAN_ALL_MESSAGES':
case 'LOGOUT':
case 'PROFILE_SUCCESS':
case 'SET_APP_CONFIG':
case 'SET_RESULTS':
case '@@router/LOCATION_CHANGE':
return ''
@ -121,7 +123,9 @@ const message = (state = initial.message, action) => {
const messages = (state = initial.messages, action) => {
switch (action.type) {
case 'AUTH_ERRORS':
case 'APP_ERRORS':
return action.messages
case 'CLEAN_ALL_MESSAGES':
case 'LOGOUT':
case 'PROFILE_SUCCESS':
case '@@router/LOCATION_CHANGE':