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: 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 uploaded files
- maximum size of zip archive - 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** - **Users**

View File

@ -571,6 +571,9 @@ Examples (to update depending on your application configuration and given distri
[Install] [Install]
WantedBy=multi-user.target 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`` - for task queue workers: ``fittrackee_workers.service``
.. code-block:: .. code-block::
@ -635,7 +638,7 @@ Examples (to update depending on your application configuration and given distri
} }
.. note:: .. 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 Docker

View File

@ -196,11 +196,11 @@
</dd> </dd>
<dt class="field-even">Request JSON Object</dt> <dt class="field-even">Request JSON Object</dt>
<dd class="field-even"><ul class="simple"> <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>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_single_file_size</strong> (<em>integer</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_zip_file_size</strong> (<em>integer</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_users</strong> (<em>integer</em>) max users allowed to register on instance</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-odd">Request Headers</dt> <dt class="field-odd">Request Headers</dt>

View File

@ -149,11 +149,15 @@
<li><p><strong>Application</strong></p> <li><p><strong>Application</strong></p>
<p>The following parameters can be set:</p> <p>The following parameters can be set:</p>
<ul class="simple"> <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 uploaded files</p></li>
<li><p>maximum size of zip archive</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> </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>
<li><p><strong>Users</strong></p> <li><p><strong>Users</strong></p>
<ul class="simple"> <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> <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> </pre></div>
</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"> <ul class="simple">
<li><p>for task queue workers: <code class="docutils literal notranslate"><span class="pre">fittrackee_workers.service</span></code></p></li> <li><p>for task queue workers: <code class="docutils literal notranslate"><span class="pre">fittrackee_workers.service</span></code></p></li>
</ul> </ul>
@ -897,7 +901,7 @@ server {
</div> </div>
<div class="admonition note"> <div class="admonition note">
<p class="admonition-title">Note</p> <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> </div>
<div class="section" id="docker"> <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: 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 uploaded files
- maximum size of zip archive - 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** - **Users**

View File

@ -571,6 +571,9 @@ Examples (to update depending on your application configuration and given distri
[Install] [Install]
WantedBy=multi-user.target 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`` - for task queue workers: ``fittrackee_workers.service``
.. code-block:: .. code-block::
@ -635,7 +638,7 @@ Examples (to update depending on your application configuration and given distri
} }
.. note:: .. 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 Docker

View File

@ -12,7 +12,7 @@ from fittrackee.responses import (
from fittrackee.users.decorators import authenticate_as_admin from fittrackee.users.decorators import authenticate_as_admin
from .models import AppConfig 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__) 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) :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 boolean is_registration_enabled: is registration enabled ?
:<json integrer max_single_file_size: max size of a single file :<json integer max_single_file_size: max size of a single file
:<json integrer max_zip_file_size: max size of a zip archive :<json integer max_zip_file_size: max size of a zip archive
:<json integrer max_users: max users allowed to register on instance :<json integer max_users: max users allowed to register on instance
:reqheader Authorization: OAuth 2.0 Bearer Token :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: if not config_data:
return InvalidPayloadErrorResponse() return InvalidPayloadErrorResponse()
ret = verify_app_config(config_data)
if ret:
return InvalidPayloadErrorResponse(message=ret)
try: try:
config = AppConfig.query.one() config = AppConfig.query.one()
if 'gpx_limit_import' in config_data: 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: if 'max_users' in config_data:
config.max_users = config_data.get('max_users') 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() db.session.commit()
update_app_config_from_database(current_app, config) update_app_config_from_database(current_app, config)
return {'status': 'success', 'data': config.serialize()} return {'status': 'success', 'data': config.serialize()}

View File

@ -1,5 +1,5 @@
import os import os
from typing import Tuple from typing import Dict, List, Tuple
from flask import Flask from flask import Flask
@ -49,3 +49,30 @@ def update_app_config_from_database(
current_app.config[ current_app.config[
'is_registration_enabled' 'is_registration_enabled'
] = db_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": { "files": {
"main.css": "/static/css/main.376b8924.chunk.css", "main.css": "/static/css/main.47c735b4.chunk.css",
"main.js": "/static/js/main.8faa878d.chunk.js", "main.js": "/static/js/main.75f806db.chunk.js",
"main.js.map": "/static/js/main.8faa878d.chunk.js.map", "main.js.map": "/static/js/main.75f806db.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.1240af94.js", "runtime-main.js": "/static/js/runtime-main.1240af94.js",
"runtime-main.js.map": "/static/js/runtime-main.1240af94.js.map", "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": "/static/js/2.301144a0.chunk.js",
"static/js/2.301144a0.chunk.js.map": "/static/js/2.301144a0.chunk.js.map", "static/js/2.301144a0.chunk.js.map": "/static/js/2.301144a0.chunk.js.map",
"index.html": "/index.html", "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/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/en.9e6dbfb0.svg": "/static/media/en.9e6dbfb0.svg",
"static/media/fr.d0f9280c.svg": "/static/media/fr.d0f9280c.svg", "static/media/fr.d0f9280c.svg": "/static/media/fr.d0f9280c.svg",
@ -18,7 +18,7 @@
"entrypoints": [ "entrypoints": [
"static/js/runtime-main.1240af94.js", "static/js/runtime-main.1240af94.js",
"static/js/2.301144a0.chunk.js", "static/js/2.301144a0.chunk.js",
"static/css/main.376b8924.chunk.css", "static/css/main.47c735b4.chunk.css",
"static/js/main.8faa878d.chunk.js" "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 [] 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): class HttpResponse(Response):
def __init__( def __init__(
self, self,
@ -32,7 +47,10 @@ class HttpResponse(Response):
class GenericErrorResponse(HttpResponse): class GenericErrorResponse(HttpResponse):
def __init__( 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: ) -> None:
response = { response = {
'status': 'error' if status is None else status, 'status': 'error' if status is None else status,
@ -46,7 +64,9 @@ class GenericErrorResponse(HttpResponse):
class InvalidPayloadErrorResponse(GenericErrorResponse): class InvalidPayloadErrorResponse(GenericErrorResponse):
def __init__( def __init__(
self, message: Optional[str] = None, status: Optional[str] = None self,
message: Optional[Union[str, List]] = None,
status: Optional[str] = None,
) -> None: ) -> None:
message = 'Invalid payload.' if message is None else message message = 'Invalid payload.' if message is None else message
super().__init__(status_code=400, message=message, status=status) super().__init__(status_code=400, message=message, status=status)
@ -101,7 +121,19 @@ class DataNotFoundErrorResponse(HttpResponse):
class PayloadTooLargeErrorResponse(GenericErrorResponse): 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') 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 fittrackee.users.models import User
from ..api_test_case import ApiTestCaseMixin
class TestGetConfig:
class TestGetConfig(ApiTestCaseMixin):
def test_it_gets_application_config( def test_it_gets_application_config(
self, app: Flask, user_1: User self, app: Flask, user_1: User
) -> None: ) -> None:
client = app.test_client() client, auth_token = self.get_test_client_and_auth_token(app)
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
response = client.get( response = client.get(
'/api/config', '/api/config',
headers=dict( headers=dict(Authorization=f'Bearer {auth_token}'),
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
) )
data = json.loads(response.data.decode()) data = json.loads(response.data.decode())
@ -41,22 +35,14 @@ class TestGetConfig:
def test_it_returns_error_if_application_has_no_config( def test_it_returns_error_if_application_has_no_config(
self, app_no_config: Flask, user_1_admin: User self, app_no_config: Flask, user_1_admin: User
) -> None: ) -> None:
client = app_no_config.test_client() client, auth_token = self.get_test_client_and_auth_token(
resp_login = client.post( app_no_config, as_admin=True
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
) )
response = client.get( response = client.get(
'/api/config', '/api/config',
content_type='application/json', content_type='application/json',
headers=dict( headers=dict(Authorization=f'Bearer {auth_token}'),
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
) )
data = json.loads(response.data.decode()) data = json.loads(response.data.decode())
@ -67,22 +53,14 @@ class TestGetConfig:
def test_it_returns_error_if_application_has_several_config( def test_it_returns_error_if_application_has_several_config(
self, app: Flask, app_config: Flask, user_1_admin: User self, app: Flask, app_config: Flask, user_1_admin: User
) -> None: ) -> None:
client = app.test_client() client, auth_token = self.get_test_client_and_auth_token(
resp_login = client.post( app, as_admin=True
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
) )
response = client.get( response = client.get(
'/api/config', '/api/config',
content_type='application/json', content_type='application/json',
headers=dict( headers=dict(Authorization=f'Bearer {auth_token}'),
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
) )
data = json.loads(response.data.decode()) data = json.loads(response.data.decode())
@ -91,26 +69,18 @@ class TestGetConfig:
assert 'Error on getting configuration.' in data['message'] assert 'Error on getting configuration.' in data['message']
class TestUpdateConfig: class TestUpdateConfig(ApiTestCaseMixin):
def test_it_updates_config_when_user_is_admin( def test_it_updates_config_when_user_is_admin(
self, app: Flask, user_1_admin: User self, app: Flask, user_1_admin: User
) -> None: ) -> None:
client = app.test_client() client, auth_token = self.get_test_client_and_auth_token(
resp_login = client.post( app, as_admin=True
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
) )
response = client.patch( response = client.patch(
'/api/config', '/api/config',
content_type='application/json', content_type='application/json',
data=json.dumps(dict(gpx_limit_import=100, max_users=10)), data=json.dumps(dict(gpx_limit_import=100, max_users=10)),
headers=dict( headers=dict(Authorization=f'Bearer {auth_token}'),
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
) )
data = json.loads(response.data.decode()) data = json.loads(response.data.decode())
@ -125,13 +95,8 @@ class TestUpdateConfig:
def test_it_updates_all_config( def test_it_updates_all_config(
self, app: Flask, user_1_admin: User self, app: Flask, user_1_admin: User
) -> None: ) -> None:
client = app.test_client() client, auth_token = self.get_test_client_and_auth_token(
resp_login = client.post( app, as_admin=True
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
) )
response = client.patch( response = client.patch(
@ -145,10 +110,7 @@ class TestUpdateConfig:
max_users=50, max_users=50,
) )
), ),
headers=dict( headers=dict(Authorization=f'Bearer {auth_token}'),
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
) )
data = json.loads(response.data.decode()) data = json.loads(response.data.decode())
@ -163,21 +125,13 @@ class TestUpdateConfig:
def test_it_returns_403_when_user_is_not_an_admin( def test_it_returns_403_when_user_is_not_an_admin(
self, app: Flask, user_1: User self, app: Flask, user_1: User
) -> None: ) -> None:
client = app.test_client() client, auth_token = self.get_test_client_and_auth_token(app)
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
response = client.patch( response = client.patch(
'/api/config', '/api/config',
content_type='application/json', content_type='application/json',
data=json.dumps(dict(gpx_limit_import=100, max_users=10)), data=json.dumps(dict(gpx_limit_import=100, max_users=10)),
headers=dict( headers=dict(Authorization=f'Bearer {auth_token}'),
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
) )
data = json.loads(response.data.decode()) data = json.loads(response.data.decode())
@ -189,23 +143,15 @@ class TestUpdateConfig:
def test_it_returns_400_if_invalid_is_payload( def test_it_returns_400_if_invalid_is_payload(
self, app: Flask, user_1_admin: User self, app: Flask, user_1_admin: User
) -> None: ) -> None:
client = app.test_client() client, auth_token = self.get_test_client_and_auth_token(
resp_login = client.post( app, as_admin=True
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
) )
response = client.patch( response = client.patch(
'/api/config', '/api/config',
content_type='application/json', content_type='application/json',
data=json.dumps(dict()), data=json.dumps(dict()),
headers=dict( headers=dict(Authorization=f'Bearer {auth_token}'),
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
) )
data = json.loads(response.data.decode()) data = json.loads(response.data.decode())
@ -216,26 +162,125 @@ class TestUpdateConfig:
def test_it_returns_error_on_update_if_application_has_no_config( def test_it_returns_error_on_update_if_application_has_no_config(
self, app_no_config: Flask, user_1_admin: User self, app_no_config: Flask, user_1_admin: User
) -> None: ) -> None:
client = app_no_config.test_client() client, auth_token = self.get_test_client_and_auth_token(
resp_login = client.post( app_no_config, as_admin=True
'/api/auth/login',
data=json.dumps(
dict(email='admin@example.com', password='12345678')
),
content_type='application/json',
) )
response = client.patch( response = client.patch(
'/api/config', '/api/config',
content_type='application/json', content_type='application/json',
data=json.dumps(dict(gpx_limit_import=100, max_users=10)), data=json.dumps(dict(gpx_limit_import=100, max_users=10)),
headers=dict( headers=dict(Authorization=f'Bearer {auth_token}'),
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
) )
data = json.loads(response.data.decode()) data = json.loads(response.data.decode())
assert response.status_code == 500 assert response.status_code == 500
assert 'error' in data['status'] assert 'error' in data['status']
assert 'Error on updating configuration.' in data['message'] 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 import os
from typing import Generator, Optional from typing import Generator, Optional, Union
import pytest import pytest
@ -11,13 +11,24 @@ from fittrackee.application.utils import update_app_config_from_database
def get_app_config( def get_app_config(
with_config: Optional[bool] = False, with_config: Optional[bool] = False,
max_workouts: Optional[int] = None, 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]: ) -> Optional[AppConfig]:
if with_config: if with_config:
config = AppConfig() config = AppConfig()
config.gpx_limit_import = 10 if max_workouts is None else max_workouts config.gpx_limit_import = 10 if max_workouts is None else max_workouts
config.max_single_file_size = 1 * 1024 * 1024 config.max_single_file_size = (
config.max_zip_file_size = 1 * 1024 * 1024 * 10 (1 if max_single_file_size is None else max_single_file_size)
config.max_users = 100 * 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.add(config)
db.session.commit() db.session.commit()
return config return config
@ -27,12 +38,21 @@ def get_app_config(
def get_app( def get_app(
with_config: Optional[bool] = False, with_config: Optional[bool] = False,
max_workouts: Optional[int] = None, 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: ) -> Generator:
app = create_app() app = create_app()
with app.app_context(): with app.app_context():
try: try:
db.create_all() 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: if app_db_config:
update_app_config_from_database(app, app_db_config) update_app_config_from_database(app, app_db_config)
yield app 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) 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 @pytest.fixture
def app_no_config() -> Generator: def app_no_config() -> Generator:
yield from get_app(with_config=False) yield from get_app(with_config=False)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,15 +1,11 @@
import re import re
from datetime import timedelta from typing import Optional, Tuple
from typing import Optional, Tuple, Union
import humanize from flask import Request
from flask import Request, current_app
from fittrackee.responses import ( from fittrackee.responses import (
ForbiddenErrorResponse, ForbiddenErrorResponse,
HttpResponse, HttpResponse,
InvalidPayloadErrorResponse,
PayloadTooLargeErrorResponse,
UnauthorizedErrorResponse, UnauthorizedErrorResponse,
) )
@ -64,49 +60,6 @@ def register_controls(
return ret 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( def verify_user(
current_request: Request, verify_admin: bool current_request: Request, verify_admin: bool
) -> Tuple[Optional[HttpResponse], Optional[int]]: ) -> Tuple[Optional[HttpResponse], Optional[int]]:
@ -139,35 +92,3 @@ def can_view_workout(
if auth_user_id != workout_user_id: if auth_user_id != workout_user_id:
return ForbiddenErrorResponse() return ForbiddenErrorResponse()
return None 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 import requests
from flask import Blueprint, Response, current_app, request, send_file from flask import Blueprint, Response, current_app, request, send_file
from sqlalchemy import exc from sqlalchemy import exc
from werkzeug.exceptions import RequestEntityTooLarge
from fittrackee import appLog, db from fittrackee import appLog, db
from fittrackee.responses import ( from fittrackee.responses import (
@ -16,14 +17,13 @@ from fittrackee.responses import (
InternalServerErrorResponse, InternalServerErrorResponse,
InvalidPayloadErrorResponse, InvalidPayloadErrorResponse,
NotFoundErrorResponse, NotFoundErrorResponse,
PayloadTooLargeErrorResponse,
handle_error_and_return_response, handle_error_and_return_response,
) )
from fittrackee.users.decorators import authenticate from fittrackee.users.decorators import authenticate
from fittrackee.users.utils import ( from fittrackee.users.models import User
User, from fittrackee.users.utils import can_view_workout
can_view_workout, from fittrackee.utils import verify_extension_and_size
verify_extension_and_size,
)
from .models import Workout from .models import Workout
from .utils import ( from .utils import (
@ -880,7 +880,15 @@ def post_workout(auth_user_id: int) -> Union[Tuple[Dict, int], HttpResponse]:
:statuscode 500: :statuscode 500:
""" """
try:
error_response = verify_extension_and_size('workout', request) 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: if error_response:
return error_response return error_response

View File

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

View File

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

View File

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

View File

@ -28,7 +28,20 @@ function Admin(props) {
<Route <Route
exact exact
path="/admin/application" 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 <Route
exact exact

View File

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

View File

@ -14,7 +14,11 @@ export default class Message extends React.PureComponent {
return ( return (
<div className="error-message"> <div className="error-message">
{singleMessage !== '' && <code>{singleMessage}</code>} {singleMessage !== '' && <code>{singleMessage}</code>}
{messages && messages.length > 0 && ( {messages &&
messages.length > 0 &&
(messages.length === 1 ? (
<code>{messages[0].value}</code>
) : (
<code> <code>
<ul> <ul>
{messages.map(msg => ( {messages.map(msg => (
@ -22,7 +26,7 @@ export default class Message extends React.PureComponent {
))} ))}
</ul> </ul>
</code> </code>
)} ))}
</div> </div>
) )
} }

View File

@ -2,7 +2,7 @@
"3 to 12 characters required for username.": "3 to 12 characters required for username.", "3 to 12 characters required for username.": "3 to 12 characters required for username.",
"8 characters required for password.": "8 characters required for password.", "8 characters required for password.": "8 characters required for password.",
"An error occurred. Please contact the administrator.": "An error occurred. Please contact the administrator.", "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 deletion.": "Error during picture deletion.",
"Error during picture update.": "Error during picture update.", "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.", "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 credentials.": "Invalid credentials.",
"Invalid payload.": "Invalid payload.", "Invalid payload.": "Invalid payload.",
"Invalid token. Please log in again.": "Invalid token. Please log in again.", "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 file part.": "No file part.",
"No picture.": "No picture.", "No picture.": "No picture.",
"No selected file.": "No selected file.", "No selected file.": "No selected file.",
@ -30,6 +34,7 @@
"statistics": "statistiques", "statistics": "statistiques",
"User does not exist.": "User does not exist.", "User does not exist.": "User does not exist.",
"Valid email must be provided.\n": "Valid email must be provided.", "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 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." "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.", "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.", "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.", "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 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.": "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", "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 credentials.": "Identifiants invalides.",
"Invalid payload.": "Données incorrectes.", "Invalid payload.": "Données incorrectes.",
"Invalid token. Please log in again.": "Jeton invalide. Merci de vous reconnecter.", "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 file part.": "Pas de fichier fourni.",
"No picture.": "Pas d'image.", "No picture.": "Pas d'image.",
"No selected file.": "Pas de fichier sélectionné.", "No selected file.": "Pas de fichier sélectionné.",
@ -30,6 +34,7 @@
"statistics": "statistics", "statistics": "statistics",
"User does not exist.": "L'utilisateur n'existe pas.", "User does not exist.": "L'utilisateur n'existe pas.",
"Valid email must be provided.\n": "L'email fourni n'est pas valide.", "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 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." "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 'PICTURE_ERROR':
case 'SET_ERROR': case 'SET_ERROR':
return action.message return action.message
case 'CLEAN_ALL_MESSAGES':
case 'LOGOUT': case 'LOGOUT':
case 'PROFILE_SUCCESS': case 'PROFILE_SUCCESS':
case 'SET_APP_CONFIG':
case 'SET_RESULTS': case 'SET_RESULTS':
case '@@router/LOCATION_CHANGE': case '@@router/LOCATION_CHANGE':
return '' return ''
@ -121,7 +123,9 @@ const message = (state = initial.message, action) => {
const messages = (state = initial.messages, action) => { const messages = (state = initial.messages, action) => {
switch (action.type) { switch (action.type) {
case 'AUTH_ERRORS': case 'AUTH_ERRORS':
case 'APP_ERRORS':
return action.messages return action.messages
case 'CLEAN_ALL_MESSAGES':
case 'LOGOUT': case 'LOGOUT':
case 'PROFILE_SUCCESS': case 'PROFILE_SUCCESS':
case '@@router/LOCATION_CHANGE': case '@@router/LOCATION_CHANGE':