Merge branch 'release-v0.6.2'

This commit is contained in:
Sam 2022-04-03 19:47:55 +02:00
commit de9eac0a92
83 changed files with 1361 additions and 1125 deletions

View File

@ -1,5 +1,17 @@
# Change log # Change log
## Version 0.6.2 (2022/04/03)
### Issues Closed
#### Bugs Fixed
* [#175](https://github.com/SamR1/FitTrackee/issues/175) - Distance card on dashboard is not refreshed
* [#173](https://github.com/SamR1/FitTrackee/issues/173) - link to user profile in workout card is incorrect
In this release 2 issues were closed.
## Version 0.6.1 (2022/03/27) ## Version 0.6.1 (2022/03/27)
### Issues Closed ### Issues Closed

View File

@ -3,14 +3,14 @@
[![PyPI version](https://img.shields.io/pypi/v/fittrackee.svg)](https://pypi.org/project/fittrackee/) [![PyPI version](https://img.shields.io/pypi/v/fittrackee.svg)](https://pypi.org/project/fittrackee/)
[![Python Version](https://img.shields.io/badge/python-3.7+-brightgreen.svg)](https://python.org) [![Python Version](https://img.shields.io/badge/python-3.7+-brightgreen.svg)](https://python.org)
[![Flask Version](https://img.shields.io/badge/flask-2.0-brightgreen.svg)](http://flask.pocoo.org/) [![Flask Version](https://img.shields.io/badge/flask-2.1-brightgreen.svg)](http://flask.pocoo.org/)
[![code style: black](https://img.shields.io/badge/code%20style-black-black)](https://github.com/psf/black) [![code style: black](https://img.shields.io/badge/code%20style-black-black)](https://github.com/psf/black)
[![type check: mypy](https://img.shields.io/badge/type%20check-mypy-blue)](http://mypy-lang.org/) [![type check: mypy](https://img.shields.io/badge/type%20check-mypy-blue)](http://mypy-lang.org/)
[![Vue Version](https://img.shields.io/badge/vue-3.2-brightgreen.svg)](https://v3.vuejs.org/) [![Vue Version](https://img.shields.io/badge/vue-3.2-brightgreen.svg)](https://v3.vuejs.org/)
[![Typescript Version](https://img.shields.io/npm/types/typescript)](https://www.typescriptlang.org/) [![Typescript Version](https://img.shields.io/npm/types/typescript)](https://www.typescriptlang.org/)
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
![pipeline status](https://github.com/SamR1/FitTrackee/actions/workflows/.tests-python.yml/badge.svg?branch=master) [![pipeline status](https://github.com/SamR1/FitTrackee/actions/workflows/.tests-python.yml/badge.svg?branch=master)](https://github.com/SamR1/FitTrackee/actions/workflows/.tests-python.yml)
![pipeline status](https://github.com/SamR1/FitTrackee/actions/workflows/.tests-javascript.yml/badge.svg?branch=master) [![pipeline status](https://github.com/SamR1/FitTrackee/actions/workflows/.tests-javascript.yml/badge.svg?branch=master)](https://github.com/SamR1/FitTrackee/actions/workflows/.tests-javascript.yml)
--- ---

View File

@ -1 +1 @@
0.6.1 0.6.2

View File

@ -1,4 +1,4 @@
# Sphinx build info version 1 # Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: 61330c9d18ff48d9802f7a0c5ced8d16 config: 2ca26683378198d52362ecd6dd5b71fe
tags: 645f666f9bcd5a90fca523b33c5a78b7 tags: 645f666f9bcd5a90fca523b33c5a78b7

Binary file not shown.

Before

Width:  |  Height:  |  Size: 538 KiB

After

Width:  |  Height:  |  Size: 539 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 368 KiB

After

Width:  |  Height:  |  Size: 368 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 KiB

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 103 KiB

View File

@ -1,5 +1,17 @@
# Change log # Change log
## Version 0.6.2 (2022/04/03)
### Issues Closed
#### Bugs Fixed
* [#175](https://github.com/SamR1/FitTrackee/issues/175) - Distance card on dashboard is not refreshed
* [#173](https://github.com/SamR1/FitTrackee/issues/173) - link to user profile in workout card is incorrect
In this release 2 issues were closed.
## Version 0.6.1 (2022/03/27) ## Version 0.6.1 (2022/03/27)
### Issues Closed ### Issues Closed

View File

@ -369,13 +369,13 @@ Production environment
.. warning:: .. warning::
| Note that FitTrackee is under heavy development, some features may be unstable. | Note that FitTrackee is under heavy development, some features may be unstable.
- Download the last release (for now, it is the release v0.6.1): - Download the last release (for now, it is the release v0.6.2):
.. code:: bash .. code:: bash
$ wget https://github.com/SamR1/FitTrackee/archive/v0.6.1.tar.gz $ wget https://github.com/SamR1/FitTrackee/archive/v0.6.2.tar.gz
$ tar -xzf v0.6.1.tar.gz $ tar -xzf v0.6.2.tar.gz
$ mv FitTrackee-0.6.1 FitTrackee $ mv FitTrackee-0.6.2 FitTrackee
$ cd FitTrackee $ cd FitTrackee
- Create **.env** from example and update it - Create **.env** from example and update it
@ -493,13 +493,13 @@ Prod environment
- Change to the directory where FitTrackee directory is located - Change to the directory where FitTrackee directory is located
- Download the last release (for now, it is the release v0.6.1) and overwrite existing files: - Download the last release (for now, it is the release v0.6.2) and overwrite existing files:
.. code:: bash .. code:: bash
$ wget https://github.com/SamR1/FitTrackee/archive/v0.6.1.tar.gz $ wget https://github.com/SamR1/FitTrackee/archive/v0.6.2.tar.gz
$ tar -xzf v0.6.1.tar.gz $ tar -xzf v0.6.2.tar.gz
$ cp -R FitTrackee-0.6.1/* FitTrackee/ $ cp -R FitTrackee-0.6.2/* FitTrackee/
$ cd FitTrackee $ cd FitTrackee
- Update **.env** if needed (see `Environment variables <installation.html#environment-variables>`__). - Update **.env** if needed (see `Environment variables <installation.html#environment-variables>`__).

View File

@ -154,9 +154,7 @@ var Documentation = {
this.fixFirefoxAnchorBug(); this.fixFirefoxAnchorBug();
this.highlightSearchWords(); this.highlightSearchWords();
this.initIndexTable(); this.initIndexTable();
if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { this.initOnKeyListeners();
this.initOnKeyListeners();
}
}, },
/** /**
@ -269,6 +267,13 @@ var Documentation = {
window.history.replaceState({}, '', url); window.history.replaceState({}, '', url);
}, },
/**
* helper function to focus on search bar
*/
focusSearchBar : function() {
$('input[name=q]').first().focus();
},
/** /**
* make the url absolute * make the url absolute
*/ */
@ -291,27 +296,54 @@ var Documentation = {
}, },
initOnKeyListeners: function() { initOnKeyListeners: function() {
// only install a listener if it is really needed
if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS &&
!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS)
return;
$(document).keydown(function(event) { $(document).keydown(function(event) {
var activeElementType = document.activeElement.tagName; var activeElementType = document.activeElement.tagName;
// don't navigate when in search box, textarea, dropdown or button // don't navigate when in search box, textarea, dropdown or button
if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT' if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT'
&& activeElementType !== 'BUTTON' && !event.altKey && !event.ctrlKey && !event.metaKey && activeElementType !== 'BUTTON') {
&& !event.shiftKey) { if (event.altKey || event.ctrlKey || event.metaKey)
switch (event.keyCode) { return;
case 37: // left
var prevHref = $('link[rel="prev"]').prop('href'); if (!event.shiftKey) {
if (prevHref) { switch (event.key) {
window.location.href = prevHref; case 'ArrowLeft':
return false; if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS)
} break;
break; var prevHref = $('link[rel="prev"]').prop('href');
case 39: // right if (prevHref) {
var nextHref = $('link[rel="next"]').prop('href'); window.location.href = prevHref;
if (nextHref) { return false;
window.location.href = nextHref; }
return false; break;
} case 'ArrowRight':
break; if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS)
break;
var nextHref = $('link[rel="next"]').prop('href');
if (nextHref) {
window.location.href = nextHref;
return false;
}
break;
case 'Escape':
if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS)
break;
Documentation.hideSearchWords();
return false;
}
}
// some keyboard layouts may need Shift to get /
switch (event.key) {
case '/':
if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS)
break;
Documentation.focusSearchBar();
return false;
} }
} }
}); });

View File

@ -1,6 +1,6 @@
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
VERSION: '0.6.1', VERSION: '0.6.2',
LANGUAGE: 'None', LANGUAGE: 'None',
COLLAPSE_INDEX: false, COLLAPSE_INDEX: false,
BUILDER: 'html', BUILDER: 'html',
@ -8,5 +8,7 @@ var DOCUMENTATION_OPTIONS = {
LINK_SUFFIX: '.html', LINK_SUFFIX: '.html',
HAS_SOURCE: true, HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt', SOURCELINK_SUFFIX: '.txt',
NAVIGATION_WITH_KEYS: false NAVIGATION_WITH_KEYS: false,
SHOW_SEARCH_SUMMARY: true,
ENABLE_SEARCH_SHORTCUTS: true,
}; };

View File

@ -172,10 +172,6 @@ var Search = {
} }
// stem the word // stem the word
var word = stemmer.stemWord(tmp[i].toLowerCase()); var word = stemmer.stemWord(tmp[i].toLowerCase());
// prevent stemmer from cutting word smaller than two chars
if(word.length < 3 && tmp[i].length >= 3) {
word = tmp[i];
}
var toAppend; var toAppend;
// select the correct list // select the correct list
if (word[0] == '-') { if (word[0] == '-') {
@ -276,7 +272,7 @@ var Search = {
setTimeout(function() { setTimeout(function() {
displayNextItem(); displayNextItem();
}, 5); }, 5);
} else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) { } else if (DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY) {
$.ajax({url: requestUrl, $.ajax({url: requestUrl,
dataType: "text", dataType: "text",
complete: function(jqxhr, textstatus) { complete: function(jqxhr, textstatus) {
@ -293,7 +289,7 @@ var Search = {
}, 5); }, 5);
}}); }});
} else { } else {
// no source available, just display title // just display title
Search.output.append(listItem); Search.output.append(listItem);
setTimeout(function() { setTimeout(function() {
displayNextItem(); displayNextItem();

View File

@ -5,7 +5,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>Authentication &#8212; FitTrackee 0.6.1 <title>Authentication &#8212; FitTrackee 0.6.2
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.6.1 <span class="navbar-text navbar-version pull-left"><b>0.6.2
</b></span> </b></span>
</div> </div>
@ -628,8 +628,9 @@ character “_” allowed</p></li>
<dt class="field-odd">Request JSON Object</dt> <dt class="field-odd">Request JSON Object</dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
<li><p><strong>timezone</strong> (<em>string</em>) user time zone</p></li> <li><p><strong>timezone</strong> (<em>string</em>) user time zone</p></li>
<li><p><strong>weekm</strong> (<em>string</em>) does week start on Monday?</p></li> <li><p><strong>weekm</strong> (<em>boolean</em>) does week start on Monday?</p></li>
<li><p><strong>language</strong> (<em>string</em>) language preferences</p></li> <li><p><strong>language</strong> (<em>string</em>) language preferences</p></li>
<li><p><strong>imperial_units</strong> (<em>boolean</em>) display distance in imperial units</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers</dt>
@ -1103,7 +1104,7 @@ character “_” allowed</p></li>
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.5.0.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -5,7 +5,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>Configuration &#8212; FitTrackee 0.6.1 <title>Configuration &#8212; FitTrackee 0.6.2
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.6.1 <span class="navbar-text navbar-version pull-left"><b>0.6.2
</b></span> </b></span>
</div> </div>
@ -142,13 +142,14 @@
<span class="p">{</span><span class="w"></span> <span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;data&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;data&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;admin_contact&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;admin@example.com&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;gpx_limit_import&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;gpx_limit_import&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;is_registration_enabled&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;is_registration_enabled&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;max_single_file_size&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1048576</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;max_single_file_size&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1048576</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;max_zip_file_size&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10485760</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;max_users&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;max_users&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;max_zip_file_size&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10485760</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;map_attribution&quot;</span><span class="p">:</span><span class="w"> </span><span class="nt">&quot;&amp;copy; &lt;a href=http://www.openstreetmap.org/copyright&gt;OpenStreetMap&lt;/a&gt; contributors&quot;</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;map_attribution&quot;</span><span class="p">:</span><span class="w"> </span><span class="nt">&quot;&amp;copy; &lt;a href=http://www.openstreetmap.org/copyright&gt;OpenStreetMap&lt;/a&gt; contributors&quot;</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;version&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;0.6.1&quot;</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;version&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;0.6.2&quot;</span><span class="w"></span>
<span class="w"> </span><span class="p">},</span><span class="w"></span> <span class="w"> </span><span class="p">},</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;success&quot;</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;success&quot;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span> <span class="p">}</span><span class="w"></span>
@ -182,10 +183,12 @@
<span class="w"> </span><span class="nt">&quot;data&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;data&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;admin_contact&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;admin@example.com&quot;</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;admin_contact&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;admin@example.com&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;gpx_limit_import&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;gpx_limit_import&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;is_registration_enabled&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;is_registration_enabled&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;max_single_file_size&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1048576</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;max_single_file_size&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1048576</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;max_users&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;max_zip_file_size&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10485760</span><span class="p">,</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;max_zip_file_size&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10485760</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;max_users&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;map_attribution&quot;</span><span class="p">:</span><span class="w"> </span><span class="nt">&quot;&amp;copy; &lt;a href=http://www.openstreetmap.org/copyright&gt;OpenStreetMap&lt;/a&gt; contributors&quot;</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;version&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;0.6.2&quot;</span><span class="w"></span>
<span class="w"> </span><span class="p">},</span><span class="w"></span> <span class="w"> </span><span class="p">},</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;success&quot;</span><span class="w"></span> <span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;success&quot;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span> <span class="p">}</span><span class="w"></span>
@ -198,8 +201,8 @@
<li><p><strong>gpx_limit_import</strong> (<em>integer</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>integer</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>integer</em>) max size of a zip archive</p></li>
<li><p><strong>max_users</strong> (<em>integer</em>) max users allowed to register on instance</p></li> <li><p><strong>max_users</strong> (<em>integer</em>) max users allowed to register on instance</p></li>
<li><p><strong>max_zip_file_size</strong> (<em>integer</em>) max size of a zip archive</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers</dt> <dt class="field-even">Request Headers</dt>
@ -268,7 +271,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.5.0.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -5,7 +5,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>API documentation &#8212; FitTrackee 0.6.1 <title>API documentation &#8212; FitTrackee 0.6.2
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.6.1 <span class="navbar-text navbar-version pull-left"><b>0.6.2
</b></span> </b></span>
</div> </div>
@ -154,7 +154,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.5.0.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -5,7 +5,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>Records &#8212; FitTrackee 0.6.1 <title>Records &#8212; FitTrackee 0.6.2
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.6.1 <span class="navbar-text navbar-version pull-left"><b>0.6.2
</b></span> </b></span>
</div> </div>
@ -246,7 +246,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.5.0.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -5,7 +5,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>Sports &#8212; FitTrackee 0.6.1 <title>Sports &#8212; FitTrackee 0.6.2
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.6.1 <span class="navbar-text navbar-version pull-left"><b>0.6.2
</b></span> </b></span>
</div> </div>
@ -484,7 +484,7 @@ Authenticated user must be an admin</p>
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.5.0.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -5,7 +5,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>Statistics &#8212; FitTrackee 0.6.1 <title>Statistics &#8212; FitTrackee 0.6.2
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.6.1 <span class="navbar-text navbar-version pull-left"><b>0.6.2
</b></span> </b></span>
</div> </div>
@ -411,7 +411,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.5.0.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -5,7 +5,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>Users &#8212; FitTrackee 0.6.1 <title>Users &#8212; FitTrackee 0.6.2
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.6.1 <span class="navbar-text navbar-version pull-left"><b>0.6.2
</b></span> </b></span>
</div> </div>
@ -279,7 +279,8 @@ has admin rights</p>
<dl class="http get"> <dl class="http get">
<dt class="sig sig-object http" id="get--api-users-(user_name)"> <dt class="sig sig-object http" id="get--api-users-(user_name)">
<span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/users/</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="pre">user_name</span></em><span class="sig-paren">)</span><a class="headerlink" href="#get--api-users-(user_name)" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">GET</span> </span><span class="sig-name descname"><span class="pre">/api/users/</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="pre">user_name</span></em><span class="sig-paren">)</span><a class="headerlink" href="#get--api-users-(user_name)" title="Permalink to this definition"></a></dt>
<dd><p>Get single user details. Only user with admin rights can get user details.</p> <dd><p>Get single user details. Only user with admin rights can get other users
details.</p>
<p>It returns user preferences only for authenticated user.</p> <p>It returns user preferences only for authenticated user.</p>
<p><strong>Example request</strong>:</p> <p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">GET</span> <span class="nn">/api/users/admin</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">GET</span> <span class="nn">/api/users/admin</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
@ -624,7 +625,7 @@ one admin</p>
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.5.0.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -5,7 +5,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>Workouts &#8212; FitTrackee 0.6.1 <title>Workouts &#8212; FitTrackee 0.6.2
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.6.1 <span class="navbar-text navbar-version pull-left"><b>0.6.2
</b></span> </b></span>
</div> </div>
@ -1148,7 +1148,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.5.0.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -5,7 +5,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>Change log &#8212; FitTrackee 0.6.1 <title>Change log &#8212; FitTrackee 0.6.2
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
@ -39,7 +39,7 @@
</button> </button>
<a class="navbar-brand" href="index.html"> <a class="navbar-brand" href="index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.6.1 <span class="navbar-text navbar-version pull-left"><b>0.6.2
</b></span> </b></span>
</div> </div>
@ -77,223 +77,230 @@
role="menu" role="menu"
aria-labelledby="dLabelLocalToc"><ul> aria-labelledby="dLabelLocalToc"><ul>
<li><a class="reference internal" href="#">Change log</a><ul> <li><a class="reference internal" href="#">Change log</a><ul>
<li><a class="reference internal" href="#version-0-6-1-2022-03-27">Version 0.6.1 (2022/03/27)</a><ul> <li><a class="reference internal" href="#version-0-6-2-2022-04-03">Version 0.6.2 (2022/04/03)</a><ul>
<li><a class="reference internal" href="#issues-closed">Issues Closed</a><ul> <li><a class="reference internal" href="#issues-closed">Issues Closed</a><ul>
<li><a class="reference internal" href="#bugs-fixed">Bugs Fixed</a></li> <li><a class="reference internal" href="#bugs-fixed">Bugs Fixed</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-6-0-2022-03-27">Version 0.6.0 (2022/03/27)</a><ul> <li><a class="reference internal" href="#version-0-6-1-2022-03-27">Version 0.6.1 (2022/03/27)</a><ul>
<li><a class="reference internal" href="#id1">Issues Closed</a><ul> <li><a class="reference internal" href="#id1">Issues Closed</a><ul>
<li><a class="reference internal" href="#features">Features</a></li>
<li><a class="reference internal" href="#id2">Bugs Fixed</a></li> <li><a class="reference internal" href="#id2">Bugs Fixed</a></li>
</ul> </ul>
</li> </li>
</ul>
</li>
<li><a class="reference internal" href="#version-0-6-0-2022-03-27">Version 0.6.0 (2022/03/27)</a><ul>
<li><a class="reference internal" href="#id3">Issues Closed</a><ul>
<li><a class="reference internal" href="#features">Features</a></li>
<li><a class="reference internal" href="#id4">Bugs Fixed</a></li>
</ul>
</li>
<li><a class="reference internal" href="#pull-requests">Pull Requests</a><ul> <li><a class="reference internal" href="#pull-requests">Pull Requests</a><ul>
<li><a class="reference internal" href="#id3">Bugs Fixed</a></li> <li><a class="reference internal" href="#id5">Bugs Fixed</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-5-7-2022-02-13">Version 0.5.7 (2022/02/13)</a><ul> <li><a class="reference internal" href="#version-0-5-7-2022-02-13">Version 0.5.7 (2022/02/13)</a><ul>
<li><a class="reference internal" href="#id4">Issues Closed</a><ul> <li><a class="reference internal" href="#id6">Issues Closed</a><ul>
<li><a class="reference internal" href="#misc">Misc</a></li> <li><a class="reference internal" href="#misc">Misc</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#id5">Pull Requests</a><ul> <li><a class="reference internal" href="#id7">Pull Requests</a><ul>
<li><a class="reference internal" href="#security">Security</a></li> <li><a class="reference internal" href="#security">Security</a></li>
<li><a class="reference internal" href="#id6">Misc</a></li> <li><a class="reference internal" href="#id8">Misc</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-5-6-2022-02-05">Version 0.5.6 (2022/02/05)</a><ul> <li><a class="reference internal" href="#version-0-5-6-2022-02-05">Version 0.5.6 (2022/02/05)</a><ul>
<li><a class="reference internal" href="#id7">Issues Closed</a><ul> <li><a class="reference internal" href="#id9">Issues Closed</a><ul>
<li><a class="reference internal" href="#id8">Bugs Fixed</a></li> <li><a class="reference internal" href="#id10">Bugs Fixed</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#id9">Pull Requests</a></li> <li><a class="reference internal" href="#id11">Pull Requests</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-5-5-2022-01-19">Version 0.5.5 (2022/01/19)</a><ul> <li><a class="reference internal" href="#version-0-5-5-2022-01-19">Version 0.5.5 (2022/01/19)</a><ul>
<li><a class="reference internal" href="#id10">Issues Closed</a><ul>
<li><a class="reference internal" href="#new-features">New Features</a></li>
<li><a class="reference internal" href="#id11">Bugs Fixed</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#version-0-5-4-2022-01-01">Version 0.5.4 (2022/01/01)</a><ul>
<li><a class="reference internal" href="#id12">Issues Closed</a><ul> <li><a class="reference internal" href="#id12">Issues Closed</a><ul>
<li><a class="reference internal" href="#new-features">New Features</a></li>
<li><a class="reference internal" href="#id13">Bugs Fixed</a></li> <li><a class="reference internal" href="#id13">Bugs Fixed</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-5-3-2022-01-01">Version 0.5.3 (2022/01/01)</a><ul> <li><a class="reference internal" href="#version-0-5-4-2022-01-01">Version 0.5.4 (2022/01/01)</a><ul>
<li><a class="reference internal" href="#id14">Issues Closed</a><ul> <li><a class="reference internal" href="#id14">Issues Closed</a><ul>
<li><a class="reference internal" href="#id15">Bugs Fixed</a></li> <li><a class="reference internal" href="#id15">Bugs Fixed</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-5-2-2021-12-19">Version 0.5.2 (2021/12/19)</a><ul> <li><a class="reference internal" href="#version-0-5-3-2022-01-01">Version 0.5.3 (2022/01/01)</a><ul>
<li><a class="reference internal" href="#id16">Issues Closed</a><ul> <li><a class="reference internal" href="#id16">Issues Closed</a><ul>
<li><a class="reference internal" href="#id17">New Features</a></li> <li><a class="reference internal" href="#id17">Bugs Fixed</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-5-1-2021-11-30">Version 0.5.1 (2021/11/30)</a><ul> <li><a class="reference internal" href="#version-0-5-2-2021-12-19">Version 0.5.2 (2021/12/19)</a><ul>
<li><a class="reference internal" href="#id18">Issues Closed</a><ul> <li><a class="reference internal" href="#id18">Issues Closed</a><ul>
<li><a class="reference internal" href="#id19">New Features</a></li> <li><a class="reference internal" href="#id19">New Features</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-5-0-2021-11-14">Version 0.5.0 (2021/11/14)</a><ul> <li><a class="reference internal" href="#version-0-5-1-2021-11-30">Version 0.5.1 (2021/11/30)</a><ul>
<li><a class="reference internal" href="#id20">Issues Closed</a><ul> <li><a class="reference internal" href="#id20">Issues Closed</a><ul>
<li><a class="reference internal" href="#id21">New Features</a></li> <li><a class="reference internal" href="#id21">New Features</a></li>
<li><a class="reference internal" href="#id22">Bugs Fixed</a></li>
<li><a class="reference internal" href="#id23">Misc</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#id24">Pull Requests</a></li> </ul>
</li>
<li><a class="reference internal" href="#version-0-5-0-2021-11-14">Version 0.5.0 (2021/11/14)</a><ul>
<li><a class="reference internal" href="#id22">Issues Closed</a><ul>
<li><a class="reference internal" href="#id23">New Features</a></li>
<li><a class="reference internal" href="#id24">Bugs Fixed</a></li>
<li><a class="reference internal" href="#id25">Misc</a></li>
</ul>
</li>
<li><a class="reference internal" href="#id26">Pull Requests</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-4-9-2021-07-16">Version 0.4.9 (2021/07/16)</a><ul> <li><a class="reference internal" href="#version-0-4-9-2021-07-16">Version 0.4.9 (2021/07/16)</a><ul>
<li><a class="reference internal" href="#id25">Issues Closed</a><ul> <li><a class="reference internal" href="#id27">Issues Closed</a><ul>
<li><a class="reference internal" href="#id26">New Features</a></li> <li><a class="reference internal" href="#id28">New Features</a></li>
<li><a class="reference internal" href="#id27">Bugs Fixed</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#version-0-4-8-2021-07-03">Version 0.4.8 (2021/07/03)</a><ul>
<li><a class="reference internal" href="#id28">Issues Closed</a><ul>
<li><a class="reference internal" href="#id29">Bugs Fixed</a></li> <li><a class="reference internal" href="#id29">Bugs Fixed</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-4-7-2021-04-07">Version 0.4.7 (2021/04/07)</a><ul> <li><a class="reference internal" href="#version-0-4-8-2021-07-03">Version 0.4.8 (2021/07/03)</a><ul>
<li><a class="reference internal" href="#id30">Issues Closed</a><ul> <li><a class="reference internal" href="#id30">Issues Closed</a><ul>
<li><a class="reference internal" href="#id31">Bugs Fixed</a></li> <li><a class="reference internal" href="#id31">Bugs Fixed</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#id32">Misc</a></li> </ul>
</li>
<li><a class="reference internal" href="#version-0-4-7-2021-04-07">Version 0.4.7 (2021/04/07)</a><ul>
<li><a class="reference internal" href="#id32">Issues Closed</a><ul>
<li><a class="reference internal" href="#id33">Bugs Fixed</a></li>
</ul>
</li>
<li><a class="reference internal" href="#id34">Misc</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-4-6-2021-02-21">Version 0.4.6 (2021/02/21)</a><ul> <li><a class="reference internal" href="#version-0-4-6-2021-02-21">Version 0.4.6 (2021/02/21)</a><ul>
<li><a class="reference internal" href="#id33">Issues Closed</a><ul>
<li><a class="reference internal" href="#id34">Bugs Fixed</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#version-0-4-5-2021-02-17">Version 0.4.5 (2021/02/17)</a><ul>
<li><a class="reference internal" href="#id35">Issues Closed</a><ul> <li><a class="reference internal" href="#id35">Issues Closed</a><ul>
<li><a class="reference internal" href="#id36">Bugs Fixed</a></li> <li><a class="reference internal" href="#id36">Bugs Fixed</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-4-4-2021-01-31">Version 0.4.4 (2021/01/31)</a><ul> <li><a class="reference internal" href="#version-0-4-5-2021-02-17">Version 0.4.5 (2021/02/17)</a><ul>
<li><a class="reference internal" href="#id37">Issues Closed</a><ul> <li><a class="reference internal" href="#id37">Issues Closed</a><ul>
<li><a class="reference internal" href="#id38">Bugs Fixed</a></li> <li><a class="reference internal" href="#id38">Bugs Fixed</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#id39">Misc</a></li> </ul>
</li>
<li><a class="reference internal" href="#version-0-4-4-2021-01-31">Version 0.4.4 (2021/01/31)</a><ul>
<li><a class="reference internal" href="#id39">Issues Closed</a><ul>
<li><a class="reference internal" href="#id40">Bugs Fixed</a></li>
</ul>
</li>
<li><a class="reference internal" href="#id41">Misc</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-4-3-2021-01-10">Version 0.4.3 (2021/01/10)</a><ul> <li><a class="reference internal" href="#version-0-4-3-2021-01-10">Version 0.4.3 (2021/01/10)</a><ul>
<li><a class="reference internal" href="#id40">Issues Closed</a><ul> <li><a class="reference internal" href="#id42">Issues Closed</a><ul>
<li><a class="reference internal" href="#id41">New Features</a></li> <li><a class="reference internal" href="#id43">New Features</a></li>
<li><a class="reference internal" href="#id42">Bugs Fixed</a></li> <li><a class="reference internal" href="#id44">Bugs Fixed</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-4-2-2021-01-03">Version 0.4.2 (2021/01/03)</a><ul> <li><a class="reference internal" href="#version-0-4-2-2021-01-03">Version 0.4.2 (2021/01/03)</a><ul>
<li><a class="reference internal" href="#id43">Misc</a></li> <li><a class="reference internal" href="#id45">Misc</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-4-1-2020-12-31">Version 0.4.1 (2020/12/31)</a><ul> <li><a class="reference internal" href="#version-0-4-1-2020-12-31">Version 0.4.1 (2020/12/31)</a><ul>
<li><a class="reference internal" href="#id44">Issues Closed</a><ul>
<li><a class="reference internal" href="#id45">New Features</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#version-0-4-0-fittrackee-on-pypi-2020-09-19">Version 0.4.0 - FitTrackee on PyPI (2020/09/19)</a><ul>
<li><a class="reference internal" href="#id46">Issues Closed</a><ul> <li><a class="reference internal" href="#id46">Issues Closed</a><ul>
<li><a class="reference internal" href="#id47">New Features</a></li> <li><a class="reference internal" href="#id47">New Features</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-3-0-administration-2020-07-15">Version 0.3.0 - Administration (2020/07/15)</a><ul> <li><a class="reference internal" href="#version-0-4-0-fittrackee-on-pypi-2020-09-19">Version 0.4.0 - FitTrackee on PyPI (2020/09/19)</a><ul>
<li><a class="reference internal" href="#id48">Issues Closed</a><ul> <li><a class="reference internal" href="#id48">Issues Closed</a><ul>
<li><a class="reference internal" href="#id49">New Features</a></li> <li><a class="reference internal" href="#id49">New Features</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-3-0-administration-2020-07-15">Version 0.3.0 - Administration (2020/07/15)</a><ul>
<li><a class="reference internal" href="#id50">Issues Closed</a><ul>
<li><a class="reference internal" href="#id51">New Features</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#version-0-2-5-fix-and-improvements-2020-01-31">Version 0.2.5 - Fix and improvements (2020/01/31)</a><ul> <li><a class="reference internal" href="#version-0-2-5-fix-and-improvements-2020-01-31">Version 0.2.5 - Fix and improvements (2020/01/31)</a><ul>
<li><a class="reference internal" href="#id50">Misc</a></li> <li><a class="reference internal" href="#id52">Misc</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-2-4-minor-fix-2020-01-30">Version 0.2.4 - Minor fix (2020/01/30)</a><ul> <li><a class="reference internal" href="#version-0-2-4-minor-fix-2020-01-30">Version 0.2.4 - Minor fix (2020/01/30)</a><ul>
<li><a class="reference internal" href="#id51">Issues Closed</a><ul> <li><a class="reference internal" href="#id53">Issues Closed</a><ul>
<li><a class="reference internal" href="#id52">Bugs Fixed</a></li> <li><a class="reference internal" href="#id54">Bugs Fixed</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-2-3-fittrackee-available-in-french-2019-12-29">Version 0.2.3 - FitTrackee available in French (2019/12/29)</a><ul> <li><a class="reference internal" href="#version-0-2-3-fittrackee-available-in-french-2019-12-29">Version 0.2.3 - FitTrackee available in French (2019/12/29)</a><ul>
<li><a class="reference internal" href="#id53">Issues Closed</a><ul> <li><a class="reference internal" href="#id55">Issues Closed</a><ul>
<li><a class="reference internal" href="#id54">New Features</a></li> <li><a class="reference internal" href="#id56">New Features</a></li>
<li><a class="reference internal" href="#id55">Bugs Fixed</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#version-0-2-2-statistics-fix-2019-09-23">Version 0.2.2 - Statistics fix (2019/09/23)</a><ul>
<li><a class="reference internal" href="#id56">Issues Closed</a><ul>
<li><a class="reference internal" href="#id57">Bugs Fixed</a></li> <li><a class="reference internal" href="#id57">Bugs Fixed</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-2-1-fix-and-improvements-2019-09-01">Version 0.2.1 - Fix and improvements (2019/09/01)</a><ul> <li><a class="reference internal" href="#version-0-2-2-statistics-fix-2019-09-23">Version 0.2.2 - Statistics fix (2019/09/23)</a><ul>
<li><a class="reference internal" href="#id58">Issues Closed</a><ul> <li><a class="reference internal" href="#id58">Issues Closed</a><ul>
<li><a class="reference internal" href="#id59">New Features</a></li> <li><a class="reference internal" href="#id59">Bugs Fixed</a></li>
<li><a class="reference internal" href="#id60">Bugs Fixed</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#id61">Misc</a></li> </ul>
</li>
<li><a class="reference internal" href="#version-0-2-1-fix-and-improvements-2019-09-01">Version 0.2.1 - Fix and improvements (2019/09/01)</a><ul>
<li><a class="reference internal" href="#id60">Issues Closed</a><ul>
<li><a class="reference internal" href="#id61">New Features</a></li>
<li><a class="reference internal" href="#id62">Bugs Fixed</a></li>
</ul>
</li>
<li><a class="reference internal" href="#id63">Misc</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-2-0-statistics-2019-07-07">Version 0.2.0 - Statistics (2019/07/07)</a><ul> <li><a class="reference internal" href="#version-0-2-0-statistics-2019-07-07">Version 0.2.0 - Statistics (2019/07/07)</a><ul>
<li><a class="reference internal" href="#id62">Issues Closed</a><ul> <li><a class="reference internal" href="#id64">Issues Closed</a><ul>
<li><a class="reference internal" href="#id63">New Features</a></li> <li><a class="reference internal" href="#id65">New Features</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#id64">Misc</a></li> <li><a class="reference internal" href="#id66">Misc</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-1-1-fix-and-improvements-2019-02-07">Version 0.1.1 - Fix and improvements (2019/02/07)</a><ul> <li><a class="reference internal" href="#version-0-1-1-fix-and-improvements-2019-02-07">Version 0.1.1 - Fix and improvements (2019/02/07)</a><ul>
<li><a class="reference internal" href="#id65">Issues Closed</a><ul> <li><a class="reference internal" href="#id67">Issues Closed</a><ul>
<li><a class="reference internal" href="#id66">New Features</a></li> <li><a class="reference internal" href="#id68">New Features</a></li>
<li><a class="reference internal" href="#id67">Bugs Fixed</a></li> <li><a class="reference internal" href="#id69">Bugs Fixed</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#version-0-1-0-first-release-2018-07-04">Version 0.1.0 - First release 🎉 (2018-07-04)</a><ul> <li><a class="reference internal" href="#version-0-1-0-first-release-2018-07-04">Version 0.1.0 - First release 🎉 (2018-07-04)</a><ul>
<li><a class="reference internal" href="#id68">Issues Closed</a><ul> <li><a class="reference internal" href="#id70">Issues Closed</a><ul>
<li><a class="reference internal" href="#id69">New Features</a></li> <li><a class="reference internal" href="#id71">New Features</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
@ -345,13 +352,27 @@
<section id="change-log"> <section id="change-log">
<h1>Change log<a class="headerlink" href="#change-log" title="Permalink to this headline"></a></h1> <h1>Change log<a class="headerlink" href="#change-log" title="Permalink to this headline"></a></h1>
<section id="version-0-6-1-2022-03-27"> <section id="version-0-6-2-2022-04-03">
<h2>Version 0.6.1 (2022/03/27)<a class="headerlink" href="#version-0-6-1-2022-03-27" title="Permalink to this headline"></a></h2> <h2>Version 0.6.2 (2022/04/03)<a class="headerlink" href="#version-0-6-2-2022-04-03" title="Permalink to this headline"></a></h2>
<section id="issues-closed"> <section id="issues-closed">
<h3>Issues Closed<a class="headerlink" href="#issues-closed" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#issues-closed" title="Permalink to this headline"></a></h3>
<section id="bugs-fixed"> <section id="bugs-fixed">
<h4>Bugs Fixed<a class="headerlink" href="#bugs-fixed" title="Permalink to this headline"></a></h4> <h4>Bugs Fixed<a class="headerlink" href="#bugs-fixed" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/175">#175</a> - Distance card on dashboard is not refreshed</p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/173">#173</a> - link to user profile in workout card is incorrect</p></li>
</ul>
<p>In this release 2 issues were closed.</p>
</section>
</section>
</section>
<section id="version-0-6-1-2022-03-27">
<h2>Version 0.6.1 (2022/03/27)<a class="headerlink" href="#version-0-6-1-2022-03-27" title="Permalink to this headline"></a></h2>
<section id="id1">
<h3>Issues Closed<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h3>
<section id="id2">
<h4>Bugs Fixed<a class="headerlink" href="#id2" title="Permalink to this headline"></a></h4>
<ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/171">#171</a> - Stats chart is not updated correctly</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/171">#171</a> - Stats chart is not updated correctly</p></li>
</ul> </ul>
<p>In this release 1 issue was closed.</p> <p>In this release 1 issue was closed.</p>
@ -361,8 +382,8 @@
<section id="version-0-6-0-2022-03-27"> <section id="version-0-6-0-2022-03-27">
<h2>Version 0.6.0 (2022/03/27)<a class="headerlink" href="#version-0-6-0-2022-03-27" title="Permalink to this headline"></a></h2> <h2>Version 0.6.0 (2022/03/27)<a class="headerlink" href="#version-0-6-0-2022-03-27" title="Permalink to this headline"></a></h2>
<p>This version introduces some changes on <a class="reference external" href="https://samr1.github.io/FitTrackee/features.html#account-preferences">user registration</a>.<br />From now on, a user needs to confirm his account after registration (an email with confirmation instructions is sent after registration).</p> <p>This version introduces some changes on <a class="reference external" href="https://samr1.github.io/FitTrackee/features.html#account-preferences">user registration</a>.<br />From now on, a user needs to confirm his account after registration (an email with confirmation instructions is sent after registration).</p>
<section id="id1"> <section id="id3">
<h3>Issues Closed<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id3" title="Permalink to this headline"></a></h3>
<section id="features"> <section id="features">
<h4>Features<a class="headerlink" href="#features" title="Permalink to this headline"></a></h4> <h4>Features<a class="headerlink" href="#features" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
@ -370,8 +391,8 @@
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/106">#106</a> - Allow user to update email</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/106">#106</a> - Allow user to update email</p></li>
</ul> </ul>
</section> </section>
<section id="id2"> <section id="id4">
<h4>Bugs Fixed<a class="headerlink" href="#id2" title="Permalink to this headline"></a></h4> <h4>Bugs Fixed<a class="headerlink" href="#id4" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/169">#169</a> - user picture is not refreshed after update</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/169">#169</a> - user picture is not refreshed after update</p></li>
</ul> </ul>
@ -379,8 +400,8 @@
</section> </section>
<section id="pull-requests"> <section id="pull-requests">
<h3>Pull Requests<a class="headerlink" href="#pull-requests" title="Permalink to this headline"></a></h3> <h3>Pull Requests<a class="headerlink" href="#pull-requests" title="Permalink to this headline"></a></h3>
<section id="id3"> <section id="id5">
<h4>Bugs Fixed<a class="headerlink" href="#id3" title="Permalink to this headline"></a></h4> <h4>Bugs Fixed<a class="headerlink" href="#id5" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/pull/161">#161</a> - Minor translation issue on Farthest</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/pull/161">#161</a> - Minor translation issue on Farthest</p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/pull/160">#160</a> - Minor translation issue on APP_ERROR</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/pull/160">#160</a> - Minor translation issue on APP_ERROR</p></li>
@ -395,8 +416,8 @@
<p>This release contains several fixes including security fixes.<br />Thanks to &#64;DanielSiersleben for the report.</p> <p>This release contains several fixes including security fixes.<br />Thanks to &#64;DanielSiersleben for the report.</p>
<p>And from now on, admin account is not created on application initialization.<br />A new command is added to set administration rights on the account created after registration <p>And from now on, admin account is not created on application initialization.<br />A new command is added to set administration rights on the account created after registration
(see <a class="reference external" href="https://samr1.github.io/FitTrackee/installation.html#upgrade">documentation</a>)</p> (see <a class="reference external" href="https://samr1.github.io/FitTrackee/installation.html#upgrade">documentation</a>)</p>
<section id="id4"> <section id="id6">
<h3>Issues Closed<a class="headerlink" href="#id4" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id6" title="Permalink to this headline"></a></h3>
<section id="misc"> <section id="misc">
<h4>Misc<a class="headerlink" href="#misc" title="Permalink to this headline"></a></h4> <h4>Misc<a class="headerlink" href="#misc" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
@ -404,8 +425,8 @@
</ul> </ul>
</section> </section>
</section> </section>
<section id="id5"> <section id="id7">
<h3>Pull Requests<a class="headerlink" href="#id5" title="Permalink to this headline"></a></h3> <h3>Pull Requests<a class="headerlink" href="#id7" title="Permalink to this headline"></a></h3>
<section id="security"> <section id="security">
<h4>Security<a class="headerlink" href="#security" title="Permalink to this headline"></a></h4> <h4>Security<a class="headerlink" href="#security" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
@ -423,8 +444,8 @@
</li> </li>
</ul> </ul>
</section> </section>
<section id="id6"> <section id="id8">
<h4>Misc<a class="headerlink" href="#id6" title="Permalink to this headline"></a></h4> <h4>Misc<a class="headerlink" href="#id8" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/pull/152">#152</a> - Fixes and improvements:</p> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/pull/152">#152</a> - Fixes and improvements:</p>
<ul> <ul>
@ -440,17 +461,17 @@
</section> </section>
<section id="version-0-5-6-2022-02-05"> <section id="version-0-5-6-2022-02-05">
<h2>Version 0.5.6 (2022/02/05)<a class="headerlink" href="#version-0-5-6-2022-02-05" title="Permalink to this headline"></a></h2> <h2>Version 0.5.6 (2022/02/05)<a class="headerlink" href="#version-0-5-6-2022-02-05" title="Permalink to this headline"></a></h2>
<section id="id7"> <section id="id9">
<h3>Issues Closed<a class="headerlink" href="#id7" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id9" title="Permalink to this headline"></a></h3>
<section id="id8"> <section id="id10">
<h4>Bugs Fixed<a class="headerlink" href="#id8" title="Permalink to this headline"></a></h4> <h4>Bugs Fixed<a class="headerlink" href="#id10" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/146">#146</a> - incorrect label on workouts filters</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/146">#146</a> - incorrect label on workouts filters</p></li>
</ul> </ul>
</section> </section>
</section> </section>
<section id="id9"> <section id="id11">
<h3>Pull Requests<a class="headerlink" href="#id9" title="Permalink to this headline"></a></h3> <h3>Pull Requests<a class="headerlink" href="#id11" title="Permalink to this headline"></a></h3>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/pull/145">#145</a> - fix on database models</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/pull/145">#145</a> - fix on database models</p></li>
</ul> </ul>
@ -459,8 +480,8 @@
</section> </section>
<section id="version-0-5-5-2022-01-19"> <section id="version-0-5-5-2022-01-19">
<h2>Version 0.5.5 (2022/01/19)<a class="headerlink" href="#version-0-5-5-2022-01-19" title="Permalink to this headline"></a></h2> <h2>Version 0.5.5 (2022/01/19)<a class="headerlink" href="#version-0-5-5-2022-01-19" title="Permalink to this headline"></a></h2>
<section id="id10"> <section id="id12">
<h3>Issues Closed<a class="headerlink" href="#id10" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id12" title="Permalink to this headline"></a></h3>
<section id="new-features"> <section id="new-features">
<h4>New Features<a class="headerlink" href="#new-features" title="Permalink to this headline"></a></h4> <h4>New Features<a class="headerlink" href="#new-features" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
@ -470,8 +491,8 @@
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/134">#134</a> - Wind direction</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/134">#134</a> - Wind direction</p></li>
</ul> </ul>
</section> </section>
<section id="id11"> <section id="id13">
<h4>Bugs Fixed<a class="headerlink" href="#id11" title="Permalink to this headline"></a></h4> <h4>Bugs Fixed<a class="headerlink" href="#id13" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/commit/877fa0faaabc0130402638905fe04f84563eb278">877fa0f</a> - fix sport icon color (when changed) on calendar on small resolutions</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/commit/877fa0faaabc0130402638905fe04f84563eb278">877fa0f</a> - fix sport icon color (when changed) on calendar on small resolutions</p></li>
</ul> </ul>
@ -481,10 +502,10 @@
</section> </section>
<section id="version-0-5-4-2022-01-01"> <section id="version-0-5-4-2022-01-01">
<h2>Version 0.5.4 (2022/01/01)<a class="headerlink" href="#version-0-5-4-2022-01-01" title="Permalink to this headline"></a></h2> <h2>Version 0.5.4 (2022/01/01)<a class="headerlink" href="#version-0-5-4-2022-01-01" title="Permalink to this headline"></a></h2>
<section id="id12"> <section id="id14">
<h3>Issues Closed<a class="headerlink" href="#id12" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id14" title="Permalink to this headline"></a></h3>
<section id="id13"> <section id="id15">
<h4>Bugs Fixed<a class="headerlink" href="#id13" title="Permalink to this headline"></a></h4> <h4>Bugs Fixed<a class="headerlink" href="#id15" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/131">#131</a> - No workouts displayed on calendar</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/131">#131</a> - No workouts displayed on calendar</p></li>
</ul> </ul>
@ -494,10 +515,10 @@
</section> </section>
<section id="version-0-5-3-2022-01-01"> <section id="version-0-5-3-2022-01-01">
<h2>Version 0.5.3 (2022/01/01)<a class="headerlink" href="#version-0-5-3-2022-01-01" title="Permalink to this headline"></a></h2> <h2>Version 0.5.3 (2022/01/01)<a class="headerlink" href="#version-0-5-3-2022-01-01" title="Permalink to this headline"></a></h2>
<section id="id14"> <section id="id16">
<h3>Issues Closed<a class="headerlink" href="#id14" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id16" title="Permalink to this headline"></a></h3>
<section id="id15"> <section id="id17">
<h4>Bugs Fixed<a class="headerlink" href="#id15" title="Permalink to this headline"></a></h4> <h4>Bugs Fixed<a class="headerlink" href="#id17" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/129">#129</a> - Display only active sports when editing a workout</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/129">#129</a> - Display only active sports when editing a workout</p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/127">#127</a> - parse_email_url() cant validate a legitimate EMAIL_URI such as “smtp://localhost:25”</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/127">#127</a> - parse_email_url() cant validate a legitimate EMAIL_URI such as “smtp://localhost:25”</p></li>
@ -508,10 +529,10 @@
</section> </section>
<section id="version-0-5-2-2021-12-19"> <section id="version-0-5-2-2021-12-19">
<h2>Version 0.5.2 (2021/12/19)<a class="headerlink" href="#version-0-5-2-2021-12-19" title="Permalink to this headline"></a></h2> <h2>Version 0.5.2 (2021/12/19)<a class="headerlink" href="#version-0-5-2-2021-12-19" title="Permalink to this headline"></a></h2>
<section id="id16"> <section id="id18">
<h3>Issues Closed<a class="headerlink" href="#id16" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id18" title="Permalink to this headline"></a></h3>
<section id="id17"> <section id="id19">
<h4>New Features<a class="headerlink" href="#id17" title="Permalink to this headline"></a></h4> <h4>New Features<a class="headerlink" href="#id19" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/123">#123</a> - Allow user to reset preferences for a sport</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/123">#123</a> - Allow user to reset preferences for a sport</p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/121">#121</a> - Add activity : snowshoes</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/121">#121</a> - Add activity : snowshoes</p></li>
@ -522,10 +543,10 @@
</section> </section>
<section id="version-0-5-1-2021-11-30"> <section id="version-0-5-1-2021-11-30">
<h2>Version 0.5.1 (2021/11/30)<a class="headerlink" href="#version-0-5-1-2021-11-30" title="Permalink to this headline"></a></h2> <h2>Version 0.5.1 (2021/11/30)<a class="headerlink" href="#version-0-5-1-2021-11-30" title="Permalink to this headline"></a></h2>
<section id="id18"> <section id="id20">
<h3>Issues Closed<a class="headerlink" href="#id18" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id20" title="Permalink to this headline"></a></h3>
<section id="id19"> <section id="id21">
<h4>New Features<a class="headerlink" href="#id19" title="Permalink to this headline"></a></h4> <h4>New Features<a class="headerlink" href="#id21" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/116">#116</a> - Better UI for Speed and Elevation buttons in the graph of the Workout screen</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/116">#116</a> - Better UI for Speed and Elevation buttons in the graph of the Workout screen</p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/115">#115</a> - Add option to download the GPX file of a Workout</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/115">#115</a> - Add option to download the GPX file of a Workout</p></li>
@ -537,10 +558,10 @@
</section> </section>
<section id="version-0-5-0-2021-11-14"> <section id="version-0-5-0-2021-11-14">
<h2>Version 0.5.0 (2021/11/14)<a class="headerlink" href="#version-0-5-0-2021-11-14" title="Permalink to this headline"></a></h2> <h2>Version 0.5.0 (2021/11/14)<a class="headerlink" href="#version-0-5-0-2021-11-14" title="Permalink to this headline"></a></h2>
<section id="id20"> <section id="id22">
<h3>Issues Closed<a class="headerlink" href="#id20" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id22" title="Permalink to this headline"></a></h3>
<section id="id21"> <section id="id23">
<h4>New Features<a class="headerlink" href="#id21" title="Permalink to this headline"></a></h4> <h4>New Features<a class="headerlink" href="#id23" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/99">#99</a> - Display workout with imperial units</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/99">#99</a> - Display workout with imperial units</p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/91">#91</a> - Display elevation chart with min and max altitude of workout</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/91">#91</a> - Display elevation chart with min and max altitude of workout</p></li>
@ -548,21 +569,21 @@
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/18">#18</a> - Better UI</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/18">#18</a> - Better UI</p></li>
</ul> </ul>
</section> </section>
<section id="id22"> <section id="id24">
<h4>Bugs Fixed<a class="headerlink" href="#id22" title="Permalink to this headline"></a></h4> <h4>Bugs Fixed<a class="headerlink" href="#id24" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/95">#95</a> - Some workouts seem to be missing on statistics chart</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/95">#95</a> - Some workouts seem to be missing on statistics chart</p></li>
</ul> </ul>
</section> </section>
<section id="id23"> <section id="id25">
<h4>Misc<a class="headerlink" href="#id23" title="Permalink to this headline"></a></h4> <h4>Misc<a class="headerlink" href="#id25" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/104">#104</a> - Switch to AGPLv3 license</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/104">#104</a> - Switch to AGPLv3 license</p></li>
</ul> </ul>
</section> </section>
</section> </section>
<section id="id24"> <section id="id26">
<h3>Pull Requests<a class="headerlink" href="#id24" title="Permalink to this headline"></a></h3> <h3>Pull Requests<a class="headerlink" href="#id26" title="Permalink to this headline"></a></h3>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/pull/101">#101</a> - Docker updates for full files</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/pull/101">#101</a> - Docker updates for full files</p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/pull/100">#100</a> - Add client application in docker for development</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/pull/100">#100</a> - Add client application in docker for development</p></li>
@ -579,17 +600,17 @@
</section> </section>
<section id="version-0-4-9-2021-07-16"> <section id="version-0-4-9-2021-07-16">
<h2>Version 0.4.9 (2021/07/16)<a class="headerlink" href="#version-0-4-9-2021-07-16" title="Permalink to this headline"></a></h2> <h2>Version 0.4.9 (2021/07/16)<a class="headerlink" href="#version-0-4-9-2021-07-16" title="Permalink to this headline"></a></h2>
<section id="id25"> <section id="id27">
<h3>Issues Closed<a class="headerlink" href="#id25" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id27" title="Permalink to this headline"></a></h3>
<section id="id26"> <section id="id28">
<h4>New Features<a class="headerlink" href="#id26" title="Permalink to this headline"></a></h4> <h4>New Features<a class="headerlink" href="#id28" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/83">#83</a> - allow using configured tile server to generate static maps<br /><strong>Note</strong>: to keep using the default tile server, set environment variable <code class="docutils literal notranslate"><span class="pre">DEFAULT_STATICMAP</span></code> to <code class="docutils literal notranslate"><span class="pre">True</span></code></p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/83">#83</a> - allow using configured tile server to generate static maps<br /><strong>Note</strong>: to keep using the default tile server, set environment variable <code class="docutils literal notranslate"><span class="pre">DEFAULT_STATICMAP</span></code> to <code class="docutils literal notranslate"><span class="pre">True</span></code></p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/81">#81</a> - display remaining characters in textarea</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/81">#81</a> - display remaining characters in textarea</p></li>
</ul> </ul>
</section> </section>
<section id="id27"> <section id="id29">
<h4>Bugs Fixed<a class="headerlink" href="#id27" title="Permalink to this headline"></a></h4> <h4>Bugs Fixed<a class="headerlink" href="#id29" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/82">#82</a> - a user can not modify his birth day</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/82">#82</a> - a user can not modify his birth day</p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/80">#80</a> - can not save notes with control characters</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/80">#80</a> - can not save notes with control characters</p></li>
@ -600,10 +621,10 @@
</section> </section>
<section id="version-0-4-8-2021-07-03"> <section id="version-0-4-8-2021-07-03">
<h2>Version 0.4.8 (2021/07/03)<a class="headerlink" href="#version-0-4-8-2021-07-03" title="Permalink to this headline"></a></h2> <h2>Version 0.4.8 (2021/07/03)<a class="headerlink" href="#version-0-4-8-2021-07-03" title="Permalink to this headline"></a></h2>
<section id="id28"> <section id="id30">
<h3>Issues Closed<a class="headerlink" href="#id28" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id30" title="Permalink to this headline"></a></h3>
<section id="id29"> <section id="id31">
<h4>Bugs Fixed<a class="headerlink" href="#id29" title="Permalink to this headline"></a></h4> <h4>Bugs Fixed<a class="headerlink" href="#id31" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/79">#79</a> - Fails to start after make rebuild</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/79">#79</a> - Fails to start after make rebuild</p></li>
</ul> </ul>
@ -613,17 +634,17 @@
</section> </section>
<section id="version-0-4-7-2021-04-07"> <section id="version-0-4-7-2021-04-07">
<h2>Version 0.4.7 (2021/04/07)<a class="headerlink" href="#version-0-4-7-2021-04-07" title="Permalink to this headline"></a></h2> <h2>Version 0.4.7 (2021/04/07)<a class="headerlink" href="#version-0-4-7-2021-04-07" title="Permalink to this headline"></a></h2>
<section id="id30"> <section id="id32">
<h3>Issues Closed<a class="headerlink" href="#id30" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id32" title="Permalink to this headline"></a></h3>
<section id="id31"> <section id="id33">
<h4>Bugs Fixed<a class="headerlink" href="#id31" title="Permalink to this headline"></a></h4> <h4>Bugs Fixed<a class="headerlink" href="#id33" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/75">#75</a> - Workouts on the same day are not displayed in right order</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/75">#75</a> - Workouts on the same day are not displayed in right order</p></li>
</ul> </ul>
</section> </section>
</section> </section>
<section id="id32"> <section id="id34">
<h3>Misc<a class="headerlink" href="#id32" title="Permalink to this headline"></a></h3> <h3>Misc<a class="headerlink" href="#id34" title="Permalink to this headline"></a></h3>
<ul class="simple"> <ul class="simple">
<li><p>Update Python and Javascript dependencies<br /><strong>IMPORTANT</strong>: Due to <a class="reference external" href="https://docs.sqlalchemy.org/en/14/changelog/changelog_14.html#change-3687655465c25a39b968b4f5f6e9170b">SQLAlchemy update (1.4+)</a>, engine URLs starting with <code class="docutils literal notranslate"><span class="pre">postgres://</span></code> are no longer supported. Please update <code class="docutils literal notranslate"><span class="pre">DATABASE_URL</span></code> with <code class="docutils literal notranslate"><span class="pre">postgresql://</span></code>.</p></li> <li><p>Update Python and Javascript dependencies<br /><strong>IMPORTANT</strong>: Due to <a class="reference external" href="https://docs.sqlalchemy.org/en/14/changelog/changelog_14.html#change-3687655465c25a39b968b4f5f6e9170b">SQLAlchemy update (1.4+)</a>, engine URLs starting with <code class="docutils literal notranslate"><span class="pre">postgres://</span></code> are no longer supported. Please update <code class="docutils literal notranslate"><span class="pre">DATABASE_URL</span></code> with <code class="docutils literal notranslate"><span class="pre">postgresql://</span></code>.</p></li>
</ul> </ul>
@ -632,10 +653,10 @@
</section> </section>
<section id="version-0-4-6-2021-02-21"> <section id="version-0-4-6-2021-02-21">
<h2>Version 0.4.6 (2021/02/21)<a class="headerlink" href="#version-0-4-6-2021-02-21" title="Permalink to this headline"></a></h2> <h2>Version 0.4.6 (2021/02/21)<a class="headerlink" href="#version-0-4-6-2021-02-21" title="Permalink to this headline"></a></h2>
<section id="id33"> <section id="id35">
<h3>Issues Closed<a class="headerlink" href="#id33" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id35" title="Permalink to this headline"></a></h3>
<section id="id34"> <section id="id36">
<h4>Bugs Fixed<a class="headerlink" href="#id34" title="Permalink to this headline"></a></h4> <h4>Bugs Fixed<a class="headerlink" href="#id36" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/72">#72</a> - Error message when file exceeding size is incorrect</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/72">#72</a> - Error message when file exceeding size is incorrect</p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/71">#71</a> - max size or max number of files must be greater than 0</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/71">#71</a> - max size or max number of files must be greater than 0</p></li>
@ -647,10 +668,10 @@
</section> </section>
<section id="version-0-4-5-2021-02-17"> <section id="version-0-4-5-2021-02-17">
<h2>Version 0.4.5 (2021/02/17)<a class="headerlink" href="#version-0-4-5-2021-02-17" title="Permalink to this headline"></a></h2> <h2>Version 0.4.5 (2021/02/17)<a class="headerlink" href="#version-0-4-5-2021-02-17" title="Permalink to this headline"></a></h2>
<section id="id35"> <section id="id37">
<h3>Issues Closed<a class="headerlink" href="#id35" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id37" title="Permalink to this headline"></a></h3>
<section id="id36"> <section id="id38">
<h4>Bugs Fixed<a class="headerlink" href="#id36" title="Permalink to this headline"></a></h4> <h4>Bugs Fixed<a class="headerlink" href="#id38" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/66">#66</a> - invalid gpx limit used when importing zip archive</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/66">#66</a> - invalid gpx limit used when importing zip archive</p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/64">#64</a> - Only 50 workouts per month shown in calendar</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/64">#64</a> - Only 50 workouts per month shown in calendar</p></li>
@ -661,17 +682,17 @@
</section> </section>
<section id="version-0-4-4-2021-01-31"> <section id="version-0-4-4-2021-01-31">
<h2>Version 0.4.4 (2021/01/31)<a class="headerlink" href="#version-0-4-4-2021-01-31" title="Permalink to this headline"></a></h2> <h2>Version 0.4.4 (2021/01/31)<a class="headerlink" href="#version-0-4-4-2021-01-31" title="Permalink to this headline"></a></h2>
<section id="id37"> <section id="id39">
<h3>Issues Closed<a class="headerlink" href="#id37" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id39" title="Permalink to this headline"></a></h3>
<section id="id38"> <section id="id40">
<h4>Bugs Fixed<a class="headerlink" href="#id38" title="Permalink to this headline"></a></h4> <h4>Bugs Fixed<a class="headerlink" href="#id40" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/62">#62</a> - Error when sending reset password email</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/62">#62</a> - Error when sending reset password email</p></li>
</ul> </ul>
</section> </section>
</section> </section>
<section id="id39"> <section id="id41">
<h3>Misc<a class="headerlink" href="#id39" title="Permalink to this headline"></a></h3> <h3>Misc<a class="headerlink" href="#id41" title="Permalink to this headline"></a></h3>
<ul class="simple"> <ul class="simple">
<li><p>Refactoring before introducing new features.</p></li> <li><p>Refactoring before introducing new features.</p></li>
<li><p>Add docker files for evaluation purposes.</p></li> <li><p>Add docker files for evaluation purposes.</p></li>
@ -681,16 +702,16 @@
</section> </section>
<section id="version-0-4-3-2021-01-10"> <section id="version-0-4-3-2021-01-10">
<h2>Version 0.4.3 (2021/01/10)<a class="headerlink" href="#version-0-4-3-2021-01-10" title="Permalink to this headline"></a></h2> <h2>Version 0.4.3 (2021/01/10)<a class="headerlink" href="#version-0-4-3-2021-01-10" title="Permalink to this headline"></a></h2>
<section id="id40"> <section id="id42">
<h3>Issues Closed<a class="headerlink" href="#id40" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id42" title="Permalink to this headline"></a></h3>
<section id="id41"> <section id="id43">
<h4>New Features<a class="headerlink" href="#id41" title="Permalink to this headline"></a></h4> <h4>New Features<a class="headerlink" href="#id43" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/58">#58</a> - Standardize terms used for workouts<br /><strong>Note:</strong> Database model, upload directory for workouts and API endpoints are also updated.</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/58">#58</a> - Standardize terms used for workouts<br /><strong>Note:</strong> Database model, upload directory for workouts and API endpoints are also updated.</p></li>
</ul> </ul>
</section> </section>
<section id="id42"> <section id="id44">
<h4>Bugs Fixed<a class="headerlink" href="#id42" title="Permalink to this headline"></a></h4> <h4>Bugs Fixed<a class="headerlink" href="#id44" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/59">#59</a> - No message displayed on uploading image error</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/59">#59</a> - No message displayed on uploading image error</p></li>
</ul> </ul>
@ -700,18 +721,18 @@
</section> </section>
<section id="version-0-4-2-2021-01-03"> <section id="version-0-4-2-2021-01-03">
<h2>Version 0.4.2 (2021/01/03)<a class="headerlink" href="#version-0-4-2-2021-01-03" title="Permalink to this headline"></a></h2> <h2>Version 0.4.2 (2021/01/03)<a class="headerlink" href="#version-0-4-2-2021-01-03" title="Permalink to this headline"></a></h2>
<section id="id43"> <section id="id45">
<h3>Misc<a class="headerlink" href="#id43" title="Permalink to this headline"></a></h3> <h3>Misc<a class="headerlink" href="#id45" title="Permalink to this headline"></a></h3>
<p>No new features in this release, only some refactorings before introducing <p>No new features in this release, only some refactorings before introducing
new features.</p> new features.</p>
</section> </section>
</section> </section>
<section id="version-0-4-1-2020-12-31"> <section id="version-0-4-1-2020-12-31">
<h2>Version 0.4.1 (2020/12/31)<a class="headerlink" href="#version-0-4-1-2020-12-31" title="Permalink to this headline"></a></h2> <h2>Version 0.4.1 (2020/12/31)<a class="headerlink" href="#version-0-4-1-2020-12-31" title="Permalink to this headline"></a></h2>
<section id="id44"> <section id="id46">
<h3>Issues Closed<a class="headerlink" href="#id44" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id46" title="Permalink to this headline"></a></h3>
<section id="id45"> <section id="id47">
<h4>New Features<a class="headerlink" href="#id45" title="Permalink to this headline"></a></h4> <h4>New Features<a class="headerlink" href="#id47" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/57">#57</a> - Use uuid for activities</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/57">#57</a> - Use uuid for activities</p></li>
</ul> </ul>
@ -727,10 +748,10 @@ new features.</p>
<li><p>Its now possible to change the tile provider for maps. The default tile server is now <strong>OpenStreetMap</strong>s standard tile layer (replacing <strong>ThunderForest Outdoors</strong>), <li><p>Its now possible to change the tile provider for maps. The default tile server is now <strong>OpenStreetMap</strong>s standard tile layer (replacing <strong>ThunderForest Outdoors</strong>),
see <a class="reference external" href="https://samr1.github.io/FitTrackee/installation.html#map-tile-server">Map tile server in documentation</a>.</p></li> see <a class="reference external" href="https://samr1.github.io/FitTrackee/installation.html#map-tile-server">Map tile server in documentation</a>.</p></li>
</ul> </ul>
<section id="id46"> <section id="id48">
<h3>Issues Closed<a class="headerlink" href="#id46" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id48" title="Permalink to this headline"></a></h3>
<section id="id47"> <section id="id49">
<h4>New Features<a class="headerlink" href="#id47" title="Permalink to this headline"></a></h4> <h4>New Features<a class="headerlink" href="#id49" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/54">#54</a> - Tile server can be changed</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/54">#54</a> - Tile server can be changed</p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/53">#53</a> - Simplify FitTrackee installation</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/53">#53</a> - Simplify FitTrackee installation</p></li>
@ -746,10 +767,10 @@ see <a class="reference external" href="https://samr1.github.io/FitTrackee/insta
<li><p>FitTrackee administration is now available (see <a class="reference external" href="https://samr1.github.io/FitTrackee/features.html#administration">documentation</a>)<br />⚠️ Warning: some application parameters move from environment variables to database (see <a class="reference external" href="https://samr1.github.io/FitTrackee/installation.html#environment-variables">installation</a>).</p></li> <li><p>FitTrackee administration is now available (see <a class="reference external" href="https://samr1.github.io/FitTrackee/features.html#administration">documentation</a>)<br />⚠️ Warning: some application parameters move from environment variables to database (see <a class="reference external" href="https://samr1.github.io/FitTrackee/installation.html#environment-variables">installation</a>).</p></li>
<li><p>in order to send emails, Redis is now a mandatory dependency</p></li> <li><p>in order to send emails, Redis is now a mandatory dependency</p></li>
</ul> </ul>
<section id="id48"> <section id="id50">
<h3>Issues Closed<a class="headerlink" href="#id48" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id50" title="Permalink to this headline"></a></h3>
<section id="id49"> <section id="id51">
<h4>New Features<a class="headerlink" href="#id49" title="Permalink to this headline"></a></h4> <h4>New Features<a class="headerlink" href="#id51" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/50">#50</a> - A user can reset his password</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/50">#50</a> - A user can reset his password</p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/17">#17</a> - A user can delete his account</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/17">#17</a> - A user can delete his account</p></li>
@ -761,8 +782,8 @@ see <a class="reference external" href="https://samr1.github.io/FitTrackee/insta
</section> </section>
<section id="version-0-2-5-fix-and-improvements-2020-01-31"> <section id="version-0-2-5-fix-and-improvements-2020-01-31">
<h2>Version 0.2.5 - Fix and improvements (2020/01/31)<a class="headerlink" href="#version-0-2-5-fix-and-improvements-2020-01-31" title="Permalink to this headline"></a></h2> <h2>Version 0.2.5 - Fix and improvements (2020/01/31)<a class="headerlink" href="#version-0-2-5-fix-and-improvements-2020-01-31" title="Permalink to this headline"></a></h2>
<section id="id50"> <section id="id52">
<h3>Misc<a class="headerlink" href="#id50" title="Permalink to this headline"></a></h3> <h3>Misc<a class="headerlink" href="#id52" title="Permalink to this headline"></a></h3>
<p>This version contains minor fix and improvements on client side:</p> <p>This version contains minor fix and improvements on client side:</p>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/commit/4c3fc343d51b9c27d3ebab71df648bcf7d7bae59">4c3fc34</a> - empty user data on logout</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/commit/4c3fc343d51b9c27d3ebab71df648bcf7d7bae59">4c3fc34</a> - empty user data on logout</p></li>
@ -775,10 +796,10 @@ add URL interceptors to simplify routes definition</p></li>
</section> </section>
<section id="version-0-2-4-minor-fix-2020-01-30"> <section id="version-0-2-4-minor-fix-2020-01-30">
<h2>Version 0.2.4 - Minor fix (2020/01/30)<a class="headerlink" href="#version-0-2-4-minor-fix-2020-01-30" title="Permalink to this headline"></a></h2> <h2>Version 0.2.4 - Minor fix (2020/01/30)<a class="headerlink" href="#version-0-2-4-minor-fix-2020-01-30" title="Permalink to this headline"></a></h2>
<section id="id51"> <section id="id53">
<h3>Issues Closed<a class="headerlink" href="#id51" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id53" title="Permalink to this headline"></a></h3>
<section id="id52"> <section id="id54">
<h4>Bugs Fixed<a class="headerlink" href="#id52" title="Permalink to this headline"></a></h4> <h4>Bugs Fixed<a class="headerlink" href="#id54" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/47">#47</a> - timezone drop-down is not displayed correctly</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/47">#47</a> - timezone drop-down is not displayed correctly</p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/46">#46</a> - calendar cannot display more than 5 or 6 activities on the same day</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/46">#46</a> - calendar cannot display more than 5 or 6 activities on the same day</p></li>
@ -789,17 +810,17 @@ add URL interceptors to simplify routes definition</p></li>
</section> </section>
<section id="version-0-2-3-fittrackee-available-in-french-2019-12-29"> <section id="version-0-2-3-fittrackee-available-in-french-2019-12-29">
<h2>Version 0.2.3 - FitTrackee available in French (2019/12/29)<a class="headerlink" href="#version-0-2-3-fittrackee-available-in-french-2019-12-29" title="Permalink to this headline"></a></h2> <h2>Version 0.2.3 - FitTrackee available in French (2019/12/29)<a class="headerlink" href="#version-0-2-3-fittrackee-available-in-french-2019-12-29" title="Permalink to this headline"></a></h2>
<section id="id53"> <section id="id55">
<h3>Issues Closed<a class="headerlink" href="#id53" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id55" title="Permalink to this headline"></a></h3>
<section id="id54"> <section id="id56">
<h4>New Features<a class="headerlink" href="#id54" title="Permalink to this headline"></a></h4> <h4>New Features<a class="headerlink" href="#id56" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/43">#43</a> - Display weekend days with a different background color on calendar</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/43">#43</a> - Display weekend days with a different background color on calendar</p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/40">#40</a> - Localize FitTrackee (i18n)</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/40">#40</a> - Localize FitTrackee (i18n)</p></li>
</ul> </ul>
</section> </section>
<section id="id55"> <section id="id57">
<h4>Bugs Fixed<a class="headerlink" href="#id55" title="Permalink to this headline"></a></h4> <h4>Bugs Fixed<a class="headerlink" href="#id57" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/44">#44</a> - Cannot edit an activity that does not have a gpx file</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/44">#44</a> - Cannot edit an activity that does not have a gpx file</p></li>
</ul> </ul>
@ -809,10 +830,10 @@ add URL interceptors to simplify routes definition</p></li>
</section> </section>
<section id="version-0-2-2-statistics-fix-2019-09-23"> <section id="version-0-2-2-statistics-fix-2019-09-23">
<h2>Version 0.2.2 - Statistics fix (2019/09/23)<a class="headerlink" href="#version-0-2-2-statistics-fix-2019-09-23" title="Permalink to this headline"></a></h2> <h2>Version 0.2.2 - Statistics fix (2019/09/23)<a class="headerlink" href="#version-0-2-2-statistics-fix-2019-09-23" title="Permalink to this headline"></a></h2>
<section id="id56"> <section id="id58">
<h3>Issues Closed<a class="headerlink" href="#id56" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id58" title="Permalink to this headline"></a></h3>
<section id="id57"> <section id="id59">
<h4>Bugs Fixed<a class="headerlink" href="#id57" title="Permalink to this headline"></a></h4> <h4>Bugs Fixed<a class="headerlink" href="#id59" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/41">#41</a> - User statistics are incorrect</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/41">#41</a> - User statistics are incorrect</p></li>
</ul> </ul>
@ -822,10 +843,10 @@ add URL interceptors to simplify routes definition</p></li>
</section> </section>
<section id="version-0-2-1-fix-and-improvements-2019-09-01"> <section id="version-0-2-1-fix-and-improvements-2019-09-01">
<h2>Version 0.2.1 - Fix and improvements (2019/09/01)<a class="headerlink" href="#version-0-2-1-fix-and-improvements-2019-09-01" title="Permalink to this headline"></a></h2> <h2>Version 0.2.1 - Fix and improvements (2019/09/01)<a class="headerlink" href="#version-0-2-1-fix-and-improvements-2019-09-01" title="Permalink to this headline"></a></h2>
<section id="id58"> <section id="id60">
<h3>Issues Closed<a class="headerlink" href="#id58" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id60" title="Permalink to this headline"></a></h3>
<section id="id59"> <section id="id61">
<h4>New Features<a class="headerlink" href="#id59" title="Permalink to this headline"></a></h4> <h4>New Features<a class="headerlink" href="#id61" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/4">#4</a> - Show points on the map when mouse over the chart</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/4">#4</a> - Show points on the map when mouse over the chart</p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/14">#14</a> - Display segments informations</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/14">#14</a> - Display segments informations</p></li>
@ -836,15 +857,15 @@ add URL interceptors to simplify routes definition</p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/37">#37</a> - Display map on activities list</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/37">#37</a> - Display map on activities list</p></li>
</ul> </ul>
</section> </section>
<section id="id60"> <section id="id62">
<h4>Bugs Fixed<a class="headerlink" href="#id60" title="Permalink to this headline"></a></h4> <h4>Bugs Fixed<a class="headerlink" href="#id62" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/34">#34</a> - Weather is not displayed anymore</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/34">#34</a> - Weather is not displayed anymore</p></li>
</ul> </ul>
</section> </section>
</section> </section>
<section id="id61"> <section id="id63">
<h3>Misc<a class="headerlink" href="#id61" title="Permalink to this headline"></a></h3> <h3>Misc<a class="headerlink" href="#id63" title="Permalink to this headline"></a></h3>
<ul class="simple"> <ul class="simple">
<li><p><strong><a class="reference external" href="https://poetry.eustace.io/">Poetry</a></strong> replaces <strong><a class="reference external" href="https://docs.pipenv.org">pipenv</a></strong> for Python packages management</p></li> <li><p><strong><a class="reference external" href="https://poetry.eustace.io/">Poetry</a></strong> replaces <strong><a class="reference external" href="https://docs.pipenv.org">pipenv</a></strong> for Python packages management</p></li>
</ul> </ul>
@ -853,17 +874,17 @@ add URL interceptors to simplify routes definition</p></li>
</section> </section>
<section id="version-0-2-0-statistics-2019-07-07"> <section id="version-0-2-0-statistics-2019-07-07">
<h2>Version 0.2.0 - Statistics (2019/07/07)<a class="headerlink" href="#version-0-2-0-statistics-2019-07-07" title="Permalink to this headline"></a></h2> <h2>Version 0.2.0 - Statistics (2019/07/07)<a class="headerlink" href="#version-0-2-0-statistics-2019-07-07" title="Permalink to this headline"></a></h2>
<section id="id62"> <section id="id64">
<h3>Issues Closed<a class="headerlink" href="#id62" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id64" title="Permalink to this headline"></a></h3>
<section id="id63"> <section id="id65">
<h4>New Features<a class="headerlink" href="#id63" title="Permalink to this headline"></a></h4> <h4>New Features<a class="headerlink" href="#id65" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/13">#13</a> - Detailed statistics</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/13">#13</a> - Detailed statistics</p></li>
</ul> </ul>
</section> </section>
</section> </section>
<section id="id64"> <section id="id66">
<h3>Misc<a class="headerlink" href="#id64" title="Permalink to this headline"></a></h3> <h3>Misc<a class="headerlink" href="#id66" title="Permalink to this headline"></a></h3>
<ul class="simple"> <ul class="simple">
<li><p>Update dependencies</p></li> <li><p>Update dependencies</p></li>
</ul> </ul>
@ -872,17 +893,17 @@ add URL interceptors to simplify routes definition</p></li>
</section> </section>
<section id="version-0-1-1-fix-and-improvements-2019-02-07"> <section id="version-0-1-1-fix-and-improvements-2019-02-07">
<h2>Version 0.1.1 - Fix and improvements (2019/02/07)<a class="headerlink" href="#version-0-1-1-fix-and-improvements-2019-02-07" title="Permalink to this headline"></a></h2> <h2>Version 0.1.1 - Fix and improvements (2019/02/07)<a class="headerlink" href="#version-0-1-1-fix-and-improvements-2019-02-07" title="Permalink to this headline"></a></h2>
<section id="id65"> <section id="id67">
<h3>Issues Closed<a class="headerlink" href="#id65" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id67" title="Permalink to this headline"></a></h3>
<section id="id66"> <section id="id68">
<h4>New Features<a class="headerlink" href="#id66" title="Permalink to this headline"></a></h4> <h4>New Features<a class="headerlink" href="#id68" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/25">#25</a> - Display records on calendar</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/25">#25</a> - Display records on calendar</p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/22">#22</a> - Add a total on current month statistics</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/22">#22</a> - Add a total on current month statistics</p></li>
</ul> </ul>
</section> </section>
<section id="id67"> <section id="id69">
<h4>Bugs Fixed<a class="headerlink" href="#id67" title="Permalink to this headline"></a></h4> <h4>Bugs Fixed<a class="headerlink" href="#id69" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/31">#31</a> - Use moving duration for stats</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/31">#31</a> - Use moving duration for stats</p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/29">#29</a> - Pause duration calculation with segments</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/29">#29</a> - Pause duration calculation with segments</p></li>
@ -931,10 +952,10 @@ add URL interceptors to simplify routes definition</p></li>
<li><p>no administration for now</p></li> <li><p>no administration for now</p></li>
</ul> </ul>
<p>➡️ more informations: see <a class="reference external" href="https://samr1.github.io/FitTrackee/">documentation</a> and <a class="reference external" href="https://github.com/SamR1/FitTrackee/issues">current issues</a></p> <p>➡️ more informations: see <a class="reference external" href="https://samr1.github.io/FitTrackee/">documentation</a> and <a class="reference external" href="https://github.com/SamR1/FitTrackee/issues">current issues</a></p>
<section id="id68"> <section id="id70">
<h3>Issues Closed<a class="headerlink" href="#id68" title="Permalink to this headline"></a></h3> <h3>Issues Closed<a class="headerlink" href="#id70" title="Permalink to this headline"></a></h3>
<section id="id69"> <section id="id71">
<h4>New Features<a class="headerlink" href="#id69" title="Permalink to this headline"></a></h4> <h4>New Features<a class="headerlink" href="#id71" title="Permalink to this headline"></a></h4>
<ul class="simple"> <ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/11">#11</a> - Timezone support</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/11">#11</a> - Timezone support</p></li>
<li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/10">#10</a> - Add a note to an activity</p></li> <li><p><a class="reference external" href="https://github.com/SamR1/FitTrackee/issues/10">#10</a> - Add a note to an activity</p></li>
@ -962,7 +983,7 @@ add URL interceptors to simplify routes definition</p></li>
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.5.0.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -5,7 +5,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>Features &#8212; FitTrackee 0.6.1 <title>Features &#8212; FitTrackee 0.6.2
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button> </button>
<a class="navbar-brand" href="index.html"> <a class="navbar-brand" href="index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.6.1 <span class="navbar-text navbar-version pull-left"><b>0.6.2
</b></span> </b></span>
</div> </div>
@ -359,7 +359,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.5.0.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Index &#8212; FitTrackee 0.6.1 <title>Index &#8212; FitTrackee 0.6.2
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
@ -37,7 +37,7 @@
</button> </button>
<a class="navbar-brand" href="index.html"> <a class="navbar-brand" href="index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.6.1 <span class="navbar-text navbar-version pull-left"><b>0.6.2
</b></span> </b></span>
</div> </div>
@ -179,7 +179,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.5.0.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>HTTP Routing Table &#8212; FitTrackee 0.6.1 <title>HTTP Routing Table &#8212; FitTrackee 0.6.2
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
@ -44,7 +44,7 @@
</button> </button>
<a class="navbar-brand" href="index.html"> <a class="navbar-brand" href="index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.6.1 <span class="navbar-text navbar-version pull-left"><b>0.6.2
</b></span> </b></span>
</div> </div>
@ -355,7 +355,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.5.0.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -5,7 +5,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>FitTrackee &#8212; FitTrackee 0.6.1 <title>FitTrackee &#8212; FitTrackee 0.6.2
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
@ -39,7 +39,7 @@
</button> </button>
<a class="navbar-brand" href="#"> <a class="navbar-brand" href="#">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.6.1 <span class="navbar-text navbar-version pull-left"><b>0.6.2
</b></span> </b></span>
</div> </div>
@ -173,7 +173,7 @@ Map</a>.</div>
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.5.0.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -5,7 +5,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>Installation &#8212; FitTrackee 0.6.1 <title>Installation &#8212; FitTrackee 0.6.2
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button> </button>
<a class="navbar-brand" href="index.html"> <a class="navbar-brand" href="index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.6.1 <span class="navbar-text navbar-version pull-left"><b>0.6.2
</b></span> </b></span>
</div> </div>
@ -632,11 +632,11 @@ $ make install-db
</div> </div>
</div> </div>
<ul class="simple"> <ul class="simple">
<li><p>Download the last release (for now, it is the release v0.6.1):</p></li> <li><p>Download the last release (for now, it is the release v0.6.2):</p></li>
</ul> </ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ wget https://github.com/SamR1/FitTrackee/archive/v0.6.1.tar.gz <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ wget https://github.com/SamR1/FitTrackee/archive/v0.6.2.tar.gz
$ tar -xzf v0.6.1.tar.gz $ tar -xzf v0.6.2.tar.gz
$ mv FitTrackee-0.6.1 FitTrackee $ mv FitTrackee-0.6.2 FitTrackee
$ <span class="nb">cd</span> FitTrackee $ <span class="nb">cd</span> FitTrackee
</pre></div> </pre></div>
</div> </div>
@ -752,11 +752,11 @@ $ <span class="nb">source</span> .env
<ul class="simple"> <ul class="simple">
<li><p>Stop the application</p></li> <li><p>Stop the application</p></li>
<li><p>Change to the directory where FitTrackee directory is located</p></li> <li><p>Change to the directory where FitTrackee directory is located</p></li>
<li><p>Download the last release (for now, it is the release v0.6.1) and overwrite existing files:</p></li> <li><p>Download the last release (for now, it is the release v0.6.2) and overwrite existing files:</p></li>
</ul> </ul>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ wget https://github.com/SamR1/FitTrackee/archive/v0.6.1.tar.gz <div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>$ wget https://github.com/SamR1/FitTrackee/archive/v0.6.2.tar.gz
$ tar -xzf v0.6.1.tar.gz $ tar -xzf v0.6.2.tar.gz
$ cp -R FitTrackee-0.6.1/* FitTrackee/ $ cp -R FitTrackee-0.6.2/* FitTrackee/
$ <span class="nb">cd</span> FitTrackee $ <span class="nb">cd</span> FitTrackee
</pre></div> </pre></div>
</div> </div>
@ -984,7 +984,7 @@ $ make docker-build docker-run docker-init
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.5.0.<br/>
</p> </p>
</div> </div>
</footer> </footer>

Binary file not shown.

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Search &#8212; FitTrackee 0.6.1 <title>Search &#8212; FitTrackee 0.6.2
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
@ -44,7 +44,7 @@
</button> </button>
<a class="navbar-brand" href="index.html"> <a class="navbar-brand" href="index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.6.1 <span class="navbar-text navbar-version pull-left"><b>0.6.2
</b></span> </b></span>
</div> </div>
@ -149,7 +149,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.5.0.<br/>
</p> </p>
</div> </div>
</footer> </footer>

File diff suppressed because one or more lines are too long

View File

@ -5,7 +5,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>Administrator &#8212; FitTrackee 0.6.1 <title>Administrator &#8212; FitTrackee 0.6.2
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.6.1 <span class="navbar-text navbar-version pull-left"><b>0.6.2
</b></span> </b></span>
</div> </div>
@ -155,7 +155,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.5.0.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -5,7 +5,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>Troubleshooting &#8212; FitTrackee 0.6.1 <title>Troubleshooting &#8212; FitTrackee 0.6.2
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.6.1 <span class="navbar-text navbar-version pull-left"><b>0.6.2
</b></span> </b></span>
</div> </div>
@ -152,7 +152,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.5.0.<br/>
</p> </p>
</div> </div>
</footer> </footer>

View File

@ -5,7 +5,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>User &#8212; FitTrackee 0.6.1 <title>User &#8212; FitTrackee 0.6.2
documentation</title> documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" /> <link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button> </button>
<a class="navbar-brand" href="../index.html"> <a class="navbar-brand" href="../index.html">
FitTrackee</a> FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.6.1 <span class="navbar-text navbar-version pull-left"><b>0.6.2
</b></span> </b></span>
</div> </div>
@ -143,7 +143,7 @@
</p> </p>
<p> <p>
&copy; Copyright 2018 - 2022, SamR1.<br/> &copy; Copyright 2018 - 2022, SamR1.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.4.0.<br/> Created using <a href="http://sphinx-doc.org/">Sphinx</a> 4.5.0.<br/>
</p> </p>
</div> </div>
</footer> </footer>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 538 KiB

After

Width:  |  Height:  |  Size: 539 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 368 KiB

After

Width:  |  Height:  |  Size: 368 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 KiB

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 103 KiB

View File

@ -369,13 +369,13 @@ Production environment
.. warning:: .. warning::
| Note that FitTrackee is under heavy development, some features may be unstable. | Note that FitTrackee is under heavy development, some features may be unstable.
- Download the last release (for now, it is the release v0.6.1): - Download the last release (for now, it is the release v0.6.2):
.. code:: bash .. code:: bash
$ wget https://github.com/SamR1/FitTrackee/archive/v0.6.1.tar.gz $ wget https://github.com/SamR1/FitTrackee/archive/v0.6.2.tar.gz
$ tar -xzf v0.6.1.tar.gz $ tar -xzf v0.6.2.tar.gz
$ mv FitTrackee-0.6.1 FitTrackee $ mv FitTrackee-0.6.2 FitTrackee
$ cd FitTrackee $ cd FitTrackee
- Create **.env** from example and update it - Create **.env** from example and update it
@ -493,13 +493,13 @@ Prod environment
- Change to the directory where FitTrackee directory is located - Change to the directory where FitTrackee directory is located
- Download the last release (for now, it is the release v0.6.1) and overwrite existing files: - Download the last release (for now, it is the release v0.6.2) and overwrite existing files:
.. code:: bash .. code:: bash
$ wget https://github.com/SamR1/FitTrackee/archive/v0.6.1.tar.gz $ wget https://github.com/SamR1/FitTrackee/archive/v0.6.2.tar.gz
$ tar -xzf v0.6.1.tar.gz $ tar -xzf v0.6.2.tar.gz
$ cp -R FitTrackee-0.6.1/* FitTrackee/ $ cp -R FitTrackee-0.6.2/* FitTrackee/
$ cd FitTrackee $ cd FitTrackee
- Update **.env** if needed (see `Environment variables <installation.html#environment-variables>`__). - Update **.env** if needed (see `Environment variables <installation.html#environment-variables>`__).

View File

@ -19,8 +19,9 @@ from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.exc import ProgrammingError from sqlalchemy.exc import ProgrammingError
from fittrackee.emails.email import EmailService from fittrackee.emails.email import EmailService
from fittrackee.request import CustomRequest
VERSION = __version__ = '0.6.1' VERSION = __version__ = '0.6.2'
db = SQLAlchemy() db = SQLAlchemy()
bcrypt = Bcrypt() bcrypt = Bcrypt()
migrate = Migrate() migrate = Migrate()
@ -35,9 +36,17 @@ logging.basicConfig(
appLog = logging.getLogger('fittrackee') appLog = logging.getLogger('fittrackee')
class CustomFlask(Flask):
# add custom Request to handle user-agent parsing
# (removed in Werkzeug 2.1)
request_class = CustomRequest
def create_app() -> Flask: def create_app() -> Flask:
# instantiate the app # instantiate the app
app = Flask(__name__, static_folder='dist/static', template_folder='dist') app = CustomFlask(
__name__, static_folder='dist/static', template_folder='dist'
)
# set config # set config
with app.app_context(): with app.app_context():
@ -105,7 +114,7 @@ def create_app() -> Flask:
appLog.setLevel(logging.DEBUG) appLog.setLevel(logging.DEBUG)
# Enable CORS # Enable CORS
@app.after_request @app.after_request # type: ignore
def after_request(response: Response) -> Response: def after_request(response: Response) -> Response:
response.headers.add('Access-Control-Allow-Origin', '*') response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add( response.headers.add(

View File

@ -40,13 +40,14 @@ def get_application_config() -> Union[Dict, HttpResponse]:
{ {
"data": { "data": {
"admin_contact": "admin@example.com",
"gpx_limit_import": 10, "gpx_limit_import": 10,
"is_registration_enabled": false, "is_registration_enabled": false,
"max_single_file_size": 1048576, "max_single_file_size": 1048576,
"max_zip_file_size": 10485760,
"max_users": 0, "max_users": 0,
"max_zip_file_size": 10485760,
"map_attribution": "&copy; <a href=http://www.openstreetmap.org/copyright>OpenStreetMap</a> contributors" "map_attribution": "&copy; <a href=http://www.openstreetmap.org/copyright>OpenStreetMap</a> contributors"
"version": "0.6.1" "version": "0.6.2"
}, },
"status": "success" "status": "success"
} }
@ -90,10 +91,12 @@ def update_application_config(auth_user: User) -> Union[Dict, HttpResponse]:
"data": { "data": {
"admin_contact": "admin@example.com", "admin_contact": "admin@example.com",
"gpx_limit_import": 10, "gpx_limit_import": 10,
"is_registration_enabled": true, "is_registration_enabled": false,
"max_single_file_size": 1048576, "max_single_file_size": 1048576,
"max_users": 10,
"max_zip_file_size": 10485760, "max_zip_file_size": 10485760,
"max_users": 10 "map_attribution": "&copy; <a href=http://www.openstreetmap.org/copyright>OpenStreetMap</a> contributors"
"version": "0.6.2"
}, },
"status": "success" "status": "success"
} }
@ -102,8 +105,8 @@ def update_application_config(auth_user: User) -> Union[Dict, HttpResponse]:
:<json integer 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 integer max_single_file_size: max size of a single file :<json integer max_single_file_size: max size of a single file
:<json integer max_zip_file_size: max size of a zip archive
:<json integer max_users: max users allowed to register on instance :<json integer max_users: max users allowed to register on instance
:<json integer max_zip_file_size: max size of a zip archive
:reqheader Authorization: OAuth 2.0 Bearer Token :reqheader Authorization: OAuth 2.0 Bearer Token

View File

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><!--[if IE]><link rel="icon" href="/favicon.ico"><![endif]--><link rel="stylesheet" href="/static/css/fork-awesome.min.css"/><link rel="stylesheet" href="/static/css/leaflet.css"/><title>FitTrackee</title><script defer="defer" src="/static/js/chunk-vendors.c045258f.js"></script><script defer="defer" src="/static/js/app.5c12d3f9.js"></script><link href="/static/css/app.3729aa92.css" rel="stylesheet"><link rel="icon" type="image/png" sizes="32x32" href="/img/icons/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/img/icons/favicon-16x16.png"><link rel="manifest" href="/manifest.json"><meta name="theme-color" content="#4DBA87"><meta name="apple-mobile-web-app-capable" content="no"><meta name="apple-mobile-web-app-status-bar-style" content="default"><meta name="apple-mobile-web-app-title" content="fittrackee_client"><link rel="apple-touch-icon" href="/img/icons/apple-touch-icon-152x152.png"><link rel="mask-icon" href="/img/icons/safari-pinned-tab.svg" color="#4DBA87"><meta name="msapplication-TileImage" content="/img/icons/msapplication-icon-144x144.png"><meta name="msapplication-TileColor" content="#000000"></head><body><noscript><strong>We're sorry but FitTrackee doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html> <!doctype html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><!--[if IE]><link rel="icon" href="/favicon.ico"><![endif]--><link rel="stylesheet" href="/static/css/fork-awesome.min.css"/><link rel="stylesheet" href="/static/css/leaflet.css"/><title>FitTrackee</title><script defer="defer" src="/static/js/chunk-vendors.63e25135.js"></script><script defer="defer" src="/static/js/app.9fb29e8d.js"></script><link href="/static/css/app.3729aa92.css" rel="stylesheet"><link rel="icon" type="image/png" sizes="32x32" href="/img/icons/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/img/icons/favicon-16x16.png"><link rel="manifest" href="/manifest.json"><meta name="theme-color" content="#4DBA87"><meta name="apple-mobile-web-app-capable" content="no"><meta name="apple-mobile-web-app-status-bar-style" content="default"><meta name="apple-mobile-web-app-title" content="fittrackee_client"><link rel="apple-touch-icon" href="/img/icons/apple-touch-icon-152x152.png"><link rel="mask-icon" href="/img/icons/safari-pinned-tab.svg" color="#4DBA87"><meta name="msapplication-TileImage" content="/img/icons/msapplication-icon-144x144.png"><meta name="msapplication-TileColor" content="#000000"></head><body><noscript><strong>We're sorry but FitTrackee doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></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

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

24
fittrackee/request.py Normal file
View File

@ -0,0 +1,24 @@
from typing import Optional, Tuple
from flask import Request
from ua_parser import user_agent_parser
from werkzeug.user_agent import UserAgent as IUserAgent
class UserAgent(IUserAgent):
def __init__(self, string: str):
super().__init__(string)
self.platform, self.browser = self._parse_user_agent(self.string)
@staticmethod
def _parse_user_agent(
user_agent: str,
) -> Tuple[Optional[str], Optional[str]]:
parsed_string = user_agent_parser.Parse(user_agent)
platform = parsed_string.get('os', {}).get('family')
browser = parsed_string.get('user_agent', {}).get('family')
return platform, browser
class CustomRequest(Request):
user_agent_class = UserAgent

View File

@ -4,17 +4,18 @@ from typing import Optional
import pytest import pytest
from flask import Flask from flask import Flask
import fittrackee
from fittrackee.application.models import AppConfig from fittrackee.application.models import AppConfig
from fittrackee.users.models import User from fittrackee.users.models import User
from ..mixins import ApiTestCaseMixin from ..mixins import ApiTestCaseMixin
from ..utils import jsonify_dict
class TestGetConfig(ApiTestCaseMixin): class TestGetConfig(ApiTestCaseMixin):
def test_it_gets_application_config_for_unauthenticated_user( def test_it_gets_application_config_for_unauthenticated_user(
self, app: Flask self, app: Flask
) -> None: ) -> None:
app_config = AppConfig.query.first()
client = app.test_client() client = app.test_client()
response = client.get('/api/config') response = client.get('/api/config')
@ -22,18 +23,7 @@ class TestGetConfig(ApiTestCaseMixin):
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 data['data']['admin_contact'] is None assert data['data'] == jsonify_dict(app_config.serialize())
assert data['data']['gpx_limit_import'] == 10
assert data['data']['is_registration_enabled'] is True
assert data['data']['max_single_file_size'] == 1048576
assert data['data']['max_zip_file_size'] == 10485760
assert data['data']['max_users'] == 100
assert data['data']['map_attribution'] == (
'&copy; <a href="http://www.openstreetmap.org/copyright" '
'target="_blank" rel="noopener noreferrer">OpenStreetMap</a> '
'contributors'
)
assert data['data']['version'] == fittrackee.__version__
def test_it_gets_application_config( def test_it_gets_application_config(
self, app: Flask, user_1: User self, app: Flask, user_1: User

View File

@ -1,22 +1,51 @@
from flask import Flask from flask import Flask
from fittrackee import VERSION
from fittrackee.application.models import AppConfig from fittrackee.application.models import AppConfig
from fittrackee.users.models import User
class TestConfigModel: class TestConfigModel:
def test_application_config(self, app: Flask) -> None: def test_application_config(self, app: Flask) -> None:
app_config = AppConfig.query.first() app_config = AppConfig.query.first()
assert 1 == app_config.id app_config.admin_contact = 'admin@example.com'
assert app_config.is_registration_enabled is True
assert (
app_config.map_attribution
== app.config['TILE_SERVER']['ATTRIBUTION']
)
serialized_app_config = app_config.serialize() serialized_app_config = app_config.serialize()
assert serialized_app_config['gpx_limit_import'] == 10 assert (
assert serialized_app_config['is_registration_enabled'] is True serialized_app_config['admin_contact'] == app_config.admin_contact
assert serialized_app_config['max_single_file_size'] == 1048576
assert serialized_app_config['max_zip_file_size'] == 10485760
assert serialized_app_config['max_users'] == 100
assert serialized_app_config['map_attribution'] == (
'&copy; <a href="http://www.openstreetmap.org/copyright" '
'target="_blank" rel="noopener noreferrer">OpenStreetMap</a> '
'contributors'
) )
assert 'admin_contact' in serialized_app_config assert (
serialized_app_config['gpx_limit_import']
== app_config.gpx_limit_import
)
assert serialized_app_config['is_registration_enabled'] is True
assert (
serialized_app_config['max_single_file_size']
== app_config.max_single_file_size
)
assert (
serialized_app_config['max_zip_file_size']
== app_config.max_zip_file_size
)
assert serialized_app_config['max_users'] == app_config.max_users
assert (
serialized_app_config['map_attribution']
== app_config.map_attribution
)
assert serialized_app_config['version'] == VERSION
def test_it_returns_registration_disabled_when_users_count_exceeds_limit(
self, app: Flask, user_1: User, user_2: User
) -> None:
app_config = AppConfig.query.first()
app_config.max_users = 2
serialized_app_config = app_config.serialize()
assert app_config.is_registration_enabled is False
assert serialized_app_config['is_registration_enabled'] is False

View File

@ -1,6 +1,6 @@
import datetime import datetime
from io import BytesIO from io import BytesIO
from typing import Generator from typing import Generator, List
from unittest.mock import Mock, patch from unittest.mock import Mock, patch
from uuid import uuid4 from uuid import uuid4
@ -107,96 +107,105 @@ def workout_running_user_1() -> Workout:
@pytest.fixture() @pytest.fixture()
def seven_workouts_user_1() -> Workout: def seven_workouts_user_1() -> List[Workout]:
workout = Workout( workouts = []
workout_1 = Workout(
user_id=1, user_id=1,
sport_id=1, sport_id=1,
workout_date=datetime.datetime.strptime('20/03/2017', '%d/%m/%Y'), workout_date=datetime.datetime.strptime('20/03/2017', '%d/%m/%Y'),
distance=5, distance=5,
duration=datetime.timedelta(seconds=1024), duration=datetime.timedelta(seconds=1024),
) )
update_workout(workout) update_workout(workout_1)
workout.ascent = 120 workout_1.ascent = 120
workout.descent = 200 workout_1.descent = 200
db.session.add(workout) db.session.add(workout_1)
db.session.flush() db.session.flush()
workouts.append(workout_1)
workout = Workout( workout_2 = Workout(
user_id=1, user_id=1,
sport_id=1, sport_id=1,
workout_date=datetime.datetime.strptime('01/06/2017', '%d/%m/%Y'), workout_date=datetime.datetime.strptime('01/06/2017', '%d/%m/%Y'),
distance=10, distance=10,
duration=datetime.timedelta(seconds=3456), duration=datetime.timedelta(seconds=3456),
) )
update_workout(workout) update_workout(workout_2)
workout.ascent = 100 workout_2.ascent = 100
workout.descent = 80 workout_2.descent = 80
db.session.add(workout) db.session.add(workout_2)
db.session.flush() db.session.flush()
workouts.append(workout_2)
workout = Workout( workout_3 = Workout(
user_id=1, user_id=1,
sport_id=1, sport_id=1,
workout_date=datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'), workout_date=datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'),
distance=10, distance=10,
duration=datetime.timedelta(seconds=1024), duration=datetime.timedelta(seconds=1024),
) )
update_workout(workout) update_workout(workout_3)
workout.ascent = 80 workout_3.ascent = 80
workout.descent = 100 workout_3.descent = 100
db.session.add(workout) db.session.add(workout_3)
db.session.flush() db.session.flush()
workouts.append(workout_3)
workout = Workout( workout_4 = Workout(
user_id=1, user_id=1,
sport_id=1, sport_id=1,
workout_date=datetime.datetime.strptime('23/02/2018', '%d/%m/%Y'), workout_date=datetime.datetime.strptime('23/02/2018', '%d/%m/%Y'),
distance=1, distance=1,
duration=datetime.timedelta(seconds=600), duration=datetime.timedelta(seconds=600),
) )
update_workout(workout) update_workout(workout_4)
workout.ascent = 120 workout_4.ascent = 120
workout.descent = 180 workout_4.descent = 180
db.session.add(workout) db.session.add(workout_4)
db.session.flush() db.session.flush()
workouts.append(workout_4)
workout = Workout( workout_5 = Workout(
user_id=1, user_id=1,
sport_id=1, sport_id=1,
workout_date=datetime.datetime.strptime('23/02/2018', '%d/%m/%Y'), workout_date=datetime.datetime.strptime('23/02/2018', '%d/%m/%Y'),
distance=10, distance=10,
duration=datetime.timedelta(seconds=1000), duration=datetime.timedelta(seconds=1000),
) )
update_workout(workout) update_workout(workout_5)
workout.ascent = 100 workout_5.ascent = 100
workout.descent = 200 workout_5.descent = 200
db.session.add(workout) db.session.add(workout_5)
db.session.flush() db.session.flush()
workouts.append(workout_5)
workout = Workout( workout_6 = Workout(
user_id=1, user_id=1,
sport_id=1, sport_id=1,
workout_date=datetime.datetime.strptime('01/04/2018', '%d/%m/%Y'), workout_date=datetime.datetime.strptime('01/04/2018', '%d/%m/%Y'),
distance=8, distance=8,
duration=datetime.timedelta(seconds=6000), duration=datetime.timedelta(seconds=6000),
) )
update_workout(workout) update_workout(workout_6)
workout.ascent = 40 workout_6.ascent = 40
workout.descent = 20 workout_6.descent = 20
db.session.add(workout) db.session.add(workout_6)
db.session.flush() db.session.flush()
workouts.append(workout_6)
workout = Workout( workout_7 = Workout(
user_id=1, user_id=1,
sport_id=1, sport_id=1,
workout_date=datetime.datetime.strptime('09/05/2018', '%d/%m/%Y'), workout_date=datetime.datetime.strptime('09/05/2018', '%d/%m/%Y'),
distance=10, distance=10,
duration=datetime.timedelta(seconds=3000), duration=datetime.timedelta(seconds=3000),
) )
update_workout(workout) update_workout(workout_7)
db.session.add(workout) db.session.add(workout_7)
db.session.commit() db.session.commit()
return workout workouts.append(workout_7)
return workouts
@pytest.fixture() @pytest.fixture()

View File

@ -4,6 +4,7 @@ from uuid import uuid4
import pytest import pytest
from fittrackee.files import display_readable_file_size from fittrackee.files import display_readable_file_size
from fittrackee.request import UserAgent
from fittrackee.utils import get_readable_duration from fittrackee.utils import get_readable_duration
@ -42,3 +43,28 @@ class TestReadableDuration:
readable_duration = get_readable_duration(30, locale) readable_duration = get_readable_duration(30, locale)
assert readable_duration == expected_duration assert readable_duration == expected_duration
class TestParseUserAgent:
string = (
'Mozilla/5.0 (X11; Linux x86_64; rv:98.0) '
'Gecko/20100101 Firefox/98.0'
)
def test_it_returns_browser_name(self) -> None:
user_agent = UserAgent(self.string)
assert user_agent.browser == 'Firefox'
def test_it_returns_other_as_brother_name_when_empty_string_provided(
self,
) -> None:
user_agent = UserAgent('')
assert user_agent.browser == 'Other'
def test_it_returns_operating_system(self) -> None:
user_agent = UserAgent(self.string)
assert user_agent.platform == 'Linux'
def test_it_returns_other_as_os_when_empty_string_provided(self) -> None:
user_agent = UserAgent('')
assert user_agent.platform == 'Other'

View File

@ -9,9 +9,10 @@ from freezegun import freeze_time
from fittrackee.users.models import User, UserSportPreference from fittrackee.users.models import User, UserSportPreference
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
from ..mixins import ApiTestCaseMixin from ..mixins import ApiTestCaseMixin
from ..utils import jsonify_dict
USER_AGENT = ( USER_AGENT = (
'Mozilla/5.0 (X11; Linux x86_64; rv:98.0) Gecko/20100101 Firefox/98.0' 'Mozilla/5.0 (X11; Linux x86_64; rv:98.0) Gecko/20100101 Firefox/98.0'
@ -284,8 +285,8 @@ class TestUserRegistration(ApiTestCaseMixin):
{ {
'username': username, 'username': username,
'fittrackee_url': 'http://0.0.0.0:5000', 'fittrackee_url': 'http://0.0.0.0:5000',
'operating_system': 'linux', 'operating_system': 'Linux',
'browser_name': 'firefox', 'browser_name': 'Firefox',
'account_confirmation_url': ( 'account_confirmation_url': (
'http://0.0.0.0:5000/account-confirmation' 'http://0.0.0.0:5000/account-confirmation'
f'?token={expected_token}' f'?token={expected_token}'
@ -453,9 +454,7 @@ class TestUserProfile(ApiTestCaseMixin):
self.assert_401(response, 'invalid token, please log in again') self.assert_401(response, 'invalid token, please log in again')
def test_it_returns_user_minimal_profile( def test_it_returns_user(self, app: Flask, user_1: User) -> None:
self, app: Flask, user_1: User
) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
) )
@ -468,92 +467,7 @@ class TestUserProfile(ApiTestCaseMixin):
assert response.status_code == 200 assert response.status_code == 200
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'] == jsonify_dict(user_1.serialize(user_1))
assert data['data']['username'] == 'test'
assert data['data']['email'] == 'test@test.com'
assert data['data']['created_at']
assert not data['data']['admin']
assert data['data']['timezone'] is None
assert data['data']['weekm'] is False
assert data['data']['imperial_units'] is False
assert data['data']['language'] is None
assert data['data']['nb_sports'] == 0
assert data['data']['nb_workouts'] == 0
assert data['data']['records'] == []
assert data['data']['sports_list'] == []
assert data['data']['total_distance'] == 0
assert data['data']['total_duration'] == '0:00:00'
def test_it_returns_user_full_profile(
self, app: Flask, user_1_full: User
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app, user_1_full.email
)
response = client.get(
'/api/auth/profile',
headers=dict(Authorization=f'Bearer {auth_token}'),
)
assert response.status_code == 200
data = json.loads(response.data.decode())
assert data['status'] == 'success'
assert data['data'] is not None
assert data['data']['username'] == 'test'
assert data['data']['email'] == 'test@test.com'
assert data['data']['created_at']
assert not data['data']['admin']
assert data['data']['first_name'] == 'John'
assert data['data']['last_name'] == 'Doe'
assert data['data']['birth_date']
assert data['data']['bio'] == 'just a random guy'
assert data['data']['imperial_units'] is False
assert data['data']['location'] == 'somewhere'
assert data['data']['timezone'] == 'America/New_York'
assert data['data']['weekm'] is False
assert data['data']['language'] == 'en'
assert data['data']['nb_sports'] == 0
assert data['data']['nb_workouts'] == 0
assert data['data']['records'] == []
assert data['data']['sports_list'] == []
assert data['data']['total_distance'] == 0
assert data['data']['total_duration'] == '0:00:00'
def test_it_returns_user_profile_with_workouts(
self,
app: Flask,
user_1: User,
sport_1_cycling: Sport,
sport_2_running: Sport,
workout_cycling_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email
)
response = client.get(
'/api/auth/profile',
headers=dict(Authorization=f'Bearer {auth_token}'),
)
assert response.status_code == 200
data = json.loads(response.data.decode())
assert data['status'] == 'success'
assert data['data'] is not None
assert data['data']['username'] == 'test'
assert data['data']['email'] == 'test@test.com'
assert data['data']['created_at']
assert not data['data']['admin']
assert data['data']['timezone'] is None
assert data['data']['imperial_units'] is False
assert data['data']['nb_sports'] == 2
assert data['data']['nb_workouts'] == 2
assert len(data['data']['records']) == 8
assert data['data']['sports_list'] == [1, 2]
assert data['data']['total_distance'] == 22
assert data['data']['total_duration'] == '2:40:00'
class TestUserProfileUpdate(ApiTestCaseMixin): class TestUserProfileUpdate(ApiTestCaseMixin):
@ -618,25 +532,7 @@ class TestUserProfileUpdate(ApiTestCaseMixin):
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'
assert data['data']['username'] == user_1.username assert data['data'] == jsonify_dict(user_1.serialize(user_1))
assert data['data']['email'] == user_1.email
assert not data['data']['admin']
assert data['data']['created_at']
assert data['data']['first_name'] == first_name
assert data['data']['last_name'] == last_name
assert data['data']['birth_date'] == 'Tue, 01 Jan 1980 00:00:00 GMT'
assert data['data']['bio'] == bio
assert data['data']['imperial_units'] is False
assert data['data']['location'] == location
assert data['data']['timezone'] is None
assert data['data']['weekm'] is False
assert data['data']['language'] is None
assert data['data']['nb_sports'] == 0
assert data['data']['nb_workouts'] == 0
assert data['data']['records'] == []
assert data['data']['sports_list'] == []
assert data['data']['total_distance'] == 0
assert data['data']['total_duration'] == '0:00:00'
class TestUserAccountUpdate(ApiTestCaseMixin): class TestUserAccountUpdate(ApiTestCaseMixin):
@ -911,8 +807,8 @@ class TestUserAccountUpdate(ApiTestCaseMixin):
{ {
'username': user_1.username, 'username': user_1.username,
'fittrackee_url': 'http://0.0.0.0:5000', 'fittrackee_url': 'http://0.0.0.0:5000',
'operating_system': 'linux', 'operating_system': 'Linux',
'browser_name': 'firefox', 'browser_name': 'Firefox',
'new_email_address': new_email, 'new_email_address': new_email,
}, },
) )
@ -953,8 +849,8 @@ class TestUserAccountUpdate(ApiTestCaseMixin):
{ {
'username': user_1.username, 'username': user_1.username,
'fittrackee_url': 'http://0.0.0.0:5000', 'fittrackee_url': 'http://0.0.0.0:5000',
'operating_system': 'linux', 'operating_system': 'Linux',
'browser_name': 'firefox', 'browser_name': 'Firefox',
'email_confirmation_url': ( 'email_confirmation_url': (
f'http://0.0.0.0:5000/email-update?token={expected_token}' f'http://0.0.0.0:5000/email-update?token={expected_token}'
), ),
@ -1113,8 +1009,8 @@ class TestUserAccountUpdate(ApiTestCaseMixin):
{ {
'username': user_1.username, 'username': user_1.username,
'fittrackee_url': 'http://0.0.0.0:5000', 'fittrackee_url': 'http://0.0.0.0:5000',
'operating_system': 'linux', 'operating_system': 'Linux',
'browser_name': 'firefox', 'browser_name': 'Firefox',
}, },
) )
@ -1270,25 +1166,7 @@ class TestUserPreferencesUpdate(ApiTestCaseMixin):
data = json.loads(response.data.decode()) data = json.loads(response.data.decode())
assert data['status'] == 'success' assert data['status'] == 'success'
assert data['message'] == 'user preferences updated' assert data['message'] == 'user preferences updated'
assert data['data']['username'] == user_1.username assert data['data'] == jsonify_dict(user_1.serialize(user_1))
assert data['data']['email'] == user_1.email
assert not data['data']['admin']
assert data['data']['created_at']
assert data['data']['first_name'] is None
assert data['data']['last_name'] is None
assert data['data']['birth_date'] is None
assert data['data']['bio'] is None
assert data['data']['imperial_units']
assert data['data']['location'] is None
assert data['data']['timezone'] == 'America/New_York'
assert data['data']['weekm'] is True
assert data['data']['language'] == 'fr'
assert data['data']['nb_sports'] == 0
assert data['data']['nb_workouts'] == 0
assert data['data']['records'] == []
assert data['data']['sports_list'] == []
assert data['data']['total_distance'] == 0
assert data['data']['total_duration'] == '0:00:00'
class TestUserSportPreferencesUpdate(ApiTestCaseMixin): class TestUserSportPreferencesUpdate(ApiTestCaseMixin):
@ -1812,8 +1690,8 @@ class TestPasswordResetRequest(ApiTestCaseMixin):
f'http://0.0.0.0:5000/password-reset?token={token}' f'http://0.0.0.0:5000/password-reset?token={token}'
), ),
'fittrackee_url': 'http://0.0.0.0:5000', 'fittrackee_url': 'http://0.0.0.0:5000',
'operating_system': 'linux', 'operating_system': 'Linux',
'browser_name': 'firefox', 'browser_name': 'Firefox',
}, },
) )
@ -2025,8 +1903,8 @@ class TestPasswordUpdate(ApiTestCaseMixin):
{ {
'username': user_1.username, 'username': user_1.username,
'fittrackee_url': 'http://0.0.0.0:5000', 'fittrackee_url': 'http://0.0.0.0:5000',
'operating_system': 'linux', 'operating_system': 'Linux',
'browser_name': 'firefox', 'browser_name': 'Firefox',
}, },
) )
@ -2252,8 +2130,8 @@ class TestResendAccountConfirmationEmail(ApiTestCaseMixin):
{ {
'username': inactive_user.username, 'username': inactive_user.username,
'fittrackee_url': 'http://0.0.0.0:5000', 'fittrackee_url': 'http://0.0.0.0:5000',
'operating_system': 'linux', 'operating_system': 'Linux',
'browser_name': 'firefox', 'browser_name': 'Firefox',
'account_confirmation_url': ( 'account_confirmation_url': (
'http://0.0.0.0:5000/account-confirmation' 'http://0.0.0.0:5000/account-confirmation'
f'?token={expected_token}' f'?token={expected_token}'

View File

@ -10,6 +10,7 @@ from fittrackee.utils import get_readable_duration
from fittrackee.workouts.models import Sport, Workout from fittrackee.workouts.models import Sport, Workout
from ..mixins import ApiTestCaseMixin from ..mixins import ApiTestCaseMixin
from ..utils import jsonify_dict
class TestGetUser(ApiTestCaseMixin): class TestGetUser(ApiTestCaseMixin):
@ -28,6 +29,26 @@ class TestGetUser(ApiTestCaseMixin):
self.assert_403(response) self.assert_403(response)
def test_user_can_access_his_profile(
self, app: Flask, user_1: User, user_2: User
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email
)
response = client.get(
f'/api/users/{user_1.username}',
content_type='application/json',
headers=dict(Authorization=f'Bearer {auth_token}'),
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert data['status'] == 'success'
assert len(data['data']['users']) == 1
user = data['data']['users'][0]
assert user['username'] == user_1.username
def test_it_gets_inactive_user( def test_it_gets_inactive_user(
self, app: Flask, user_1_admin: User, inactive_user: User self, app: Flask, user_1_admin: User, inactive_user: User
) -> None: ) -> None:
@ -46,22 +67,7 @@ class TestGetUser(ApiTestCaseMixin):
assert data['status'] == 'success' assert data['status'] == 'success'
assert len(data['data']['users']) == 1 assert len(data['data']['users']) == 1
user = data['data']['users'][0] user = data['data']['users'][0]
assert user['username'] == inactive_user.username assert user == jsonify_dict(inactive_user.serialize(user_1_admin))
assert user['email'] == inactive_user.email
assert user['created_at']
assert not user['admin']
assert not user['is_active']
assert user['first_name'] is None
assert user['last_name'] is None
assert user['birth_date'] is None
assert user['bio'] is None
assert user['location'] is None
assert user['nb_sports'] == 0
assert user['nb_workouts'] == 0
assert user['records'] == []
assert user['sports_list'] == []
assert user['total_distance'] == 0
assert user['total_duration'] == '0:00:00'
def test_it_gets_single_user_without_workouts( def test_it_gets_single_user_without_workouts(
self, app: Flask, user_1_admin: User, user_2: User self, app: Flask, user_1_admin: User, user_2: User
@ -81,22 +87,7 @@ class TestGetUser(ApiTestCaseMixin):
assert data['status'] == 'success' assert data['status'] == 'success'
assert len(data['data']['users']) == 1 assert len(data['data']['users']) == 1
user = data['data']['users'][0] user = data['data']['users'][0]
assert user['username'] == user_2.username assert user == jsonify_dict(user_2.serialize(user_1_admin))
assert user['email'] == user_2.email
assert user['created_at']
assert not user['admin']
assert user['is_active']
assert user['first_name'] is None
assert user['last_name'] is None
assert user['birth_date'] is None
assert user['bio'] is None
assert user['location'] is None
assert user['nb_sports'] == 0
assert user['nb_workouts'] == 0
assert user['records'] == []
assert user['sports_list'] == []
assert user['total_distance'] == 0
assert user['total_duration'] == '0:00:00'
def test_it_gets_single_user_with_workouts( def test_it_gets_single_user_with_workouts(
self, self,
@ -123,22 +114,7 @@ class TestGetUser(ApiTestCaseMixin):
assert data['status'] == 'success' assert data['status'] == 'success'
assert len(data['data']['users']) == 1 assert len(data['data']['users']) == 1
user = data['data']['users'][0] user = data['data']['users'][0]
assert user['username'] == user_1.username assert user == jsonify_dict(user_1.serialize(user_2_admin))
assert user['email'] == user_1.email
assert user['created_at']
assert not user['admin']
assert user['is_active']
assert user['first_name'] is None
assert user['last_name'] is None
assert user['birth_date'] is None
assert user['bio'] is None
assert user['location'] is None
assert len(user['records']) == 8
assert user['nb_sports'] == 2
assert user['nb_workouts'] == 2
assert user['sports_list'] == [1, 2]
assert user['total_distance'] == 22
assert user['total_duration'] == '2:40:00'
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_admin: User self, app: Flask, user_1_admin: User
@ -187,106 +163,15 @@ class TestGetUsers(ApiTestCaseMixin):
assert response.status_code == 200 assert response.status_code == 200
assert 'success' in data['status'] assert 'success' in data['status']
assert len(data['data']['users']) == 3 assert len(data['data']['users']) == 3
assert 'created_at' in data['data']['users'][0] assert data['data']['users'][0] == jsonify_dict(
assert 'created_at' in data['data']['users'][1] user_1_admin.serialize(user_1_admin)
assert 'created_at' in data['data']['users'][2]
assert 'admin' in data['data']['users'][0]['username']
assert 'inactive' in data['data']['users'][1]['username']
assert 'sam' in data['data']['users'][2]['username']
assert 'admin@example.com' in data['data']['users'][0]['email']
assert 'inactive@example.com' in data['data']['users'][1]['email']
assert 'sam@test.com' in data['data']['users'][2]['email']
assert data['data']['users'][0]['is_active']
assert not data['data']['users'][1]['is_active']
assert data['data']['users'][2]['is_active']
assert data['data']['users'][0]['imperial_units'] is False
assert data['data']['users'][0]['timezone'] is None
assert data['data']['users'][0]['weekm'] is False
assert data['data']['users'][0]['language'] is None
assert data['data']['users'][0]['nb_sports'] == 0
assert data['data']['users'][0]['nb_workouts'] == 0
assert data['data']['users'][0]['records'] == []
assert data['data']['users'][0]['sports_list'] == []
assert data['data']['users'][0]['total_distance'] == 0
assert data['data']['users'][0]['total_duration'] == '0:00:00'
assert data['data']['users'][1]['nb_sports'] == 0
assert data['data']['users'][1]['nb_workouts'] == 0
assert data['data']['users'][1]['records'] == []
assert data['data']['users'][1]['sports_list'] == []
assert data['data']['users'][1]['total_distance'] == 0
assert data['data']['users'][1]['total_duration'] == '0:00:00'
assert data['data']['users'][2]['records'] == []
assert data['data']['users'][2]['nb_sports'] == 0
assert data['data']['users'][2]['nb_workouts'] == 0
assert data['data']['users'][2]['sports_list'] == []
assert data['data']['users'][2]['total_distance'] == 0
assert data['data']['users'][2]['total_duration'] == '0:00:00'
assert data['pagination'] == {
'has_next': False,
'has_prev': False,
'page': 1,
'pages': 1,
'total': 3,
}
def test_it_gets_users_list_with_workouts(
self,
app: Flask,
user_1_admin: User,
user_2: User,
user_3: User,
sport_1_cycling: Sport,
workout_cycling_user_1: Workout,
sport_2_running: Sport,
workout_running_user_1: Workout,
workout_cycling_user_2: Workout,
) -> None:
client, auth_token = self.get_test_client_and_auth_token(
app, user_1_admin.email
) )
assert data['data']['users'][1] == jsonify_dict(
response = client.get( inactive_user.serialize(user_1_admin)
'/api/users', )
headers=dict(Authorization=f'Bearer {auth_token}'), assert data['data']['users'][2] == jsonify_dict(
user_3.serialize(user_1_admin)
) )
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['users']) == 3
assert 'created_at' in data['data']['users'][0]
assert 'created_at' in data['data']['users'][1]
assert 'created_at' in data['data']['users'][2]
assert 'admin' in data['data']['users'][0]['username']
assert 'toto' in data['data']['users'][1]['username']
assert 'sam' in data['data']['users'][2]['username']
assert 'admin@example.com' in data['data']['users'][0]['email']
assert 'toto@toto.com' in data['data']['users'][1]['email']
assert 'sam@test.com' in data['data']['users'][2]['email']
assert data['data']['users'][0]['is_active']
assert data['data']['users'][1]['is_active']
assert data['data']['users'][2]['is_active']
assert data['data']['users'][0]['imperial_units'] is False
assert data['data']['users'][0]['timezone'] is None
assert data['data']['users'][0]['weekm'] is False
assert data['data']['users'][0]['nb_sports'] == 2
assert data['data']['users'][0]['nb_workouts'] == 2
assert len(data['data']['users'][0]['records']) == 8
assert data['data']['users'][0]['sports_list'] == [1, 2]
assert data['data']['users'][0]['total_distance'] == 22.0
assert data['data']['users'][0]['total_duration'] == '2:40:00'
assert data['data']['users'][1]['nb_sports'] == 1
assert data['data']['users'][1]['nb_workouts'] == 1
assert len(data['data']['users'][1]['records']) == 4
assert data['data']['users'][1]['sports_list'] == [1]
assert data['data']['users'][1]['total_distance'] == 15
assert data['data']['users'][1]['total_duration'] == '1:00:00'
assert data['data']['users'][2]['nb_sports'] == 0
assert data['data']['users'][2]['nb_workouts'] == 0
assert len(data['data']['users'][2]['records']) == 0
assert data['data']['users'][2]['sports_list'] == []
assert data['data']['users'][2]['total_distance'] == 0
assert data['data']['users'][2]['total_duration'] == '0:00:00'
assert data['pagination'] == { assert data['pagination'] == {
'has_next': False, 'has_next': False,
'has_prev': False, 'has_prev': False,

View File

@ -9,77 +9,145 @@ from fittrackee.workouts.models import Sport, Workout
class TestUserModel: class TestUserModel:
@staticmethod def test_it_returns_username_in_string_value(
def assert_serialized_used(serialized_user: Dict) -> None: self, app: Flask, user_1: User
assert 'created_at' in serialized_user ) -> None:
assert serialized_user['admin'] is False
assert serialized_user['first_name'] is None
assert serialized_user['is_active']
assert serialized_user['last_name'] is None
assert serialized_user['bio'] is None
assert serialized_user['location'] is None
assert serialized_user['birth_date'] is None
assert serialized_user['picture'] is False
assert serialized_user['nb_workouts'] == 0
def test_user_model_as_auth_user(self, app: Flask, user_1: User) -> None:
assert '<User \'test\'>' == str(user_1) assert '<User \'test\'>' == str(user_1)
class UserModelAssertMixin:
@staticmethod
def assert_user_account(serialized_user: Dict, user: User) -> None:
assert serialized_user['admin'] == user.admin
assert serialized_user['email_to_confirm'] == user.email_to_confirm
assert serialized_user['is_active'] == user.is_active
assert serialized_user['username'] == user.username
@staticmethod
def assert_user_profile(serialized_user: Dict, user: User) -> None:
assert serialized_user['bio'] == user.bio
assert serialized_user['birth_date'] == user.birth_date
assert serialized_user['first_name'] == user.first_name
assert serialized_user['last_name'] == user.last_name
assert serialized_user['location'] == user.location
assert serialized_user['picture'] is False
@staticmethod
def assert_workouts_keys_are_present(serialized_user: Dict) -> None:
assert 'nb_sports' in serialized_user
assert 'nb_workouts' in serialized_user
assert 'records' in serialized_user
assert 'sports_list' in serialized_user
assert 'total_distance' in serialized_user
assert 'total_duration' in serialized_user
class TestUserSerializeAsAuthUser(UserModelAssertMixin):
def test_it_returns_user_account_infos(
self, app: Flask, user_1: User
) -> None:
serialized_user = user_1.serialize(user_1) serialized_user = user_1.serialize(user_1)
self.assert_serialized_used(serialized_user) self.assert_user_account(serialized_user, user_1)
assert 'test' == serialized_user['username']
assert 'test@test.com' == serialized_user['email']
assert serialized_user['nb_sports'] == 0
assert serialized_user['records'] == []
assert serialized_user['sports_list'] == []
assert serialized_user['total_distance'] == 0
assert serialized_user['total_duration'] == '0:00:00'
assert serialized_user['imperial_units'] is False
assert serialized_user['language'] is None
assert serialized_user['timezone'] is None
assert serialized_user['weekm'] is False
assert serialized_user['email_to_confirm'] is None
assert 'confirmation_token' not in serialized_user
def test_user_model_as_admin( def test_it_returns_user_profile_infos(
self, app: Flask, user_1: User
) -> None:
serialized_user = user_1.serialize(user_1)
self.assert_user_profile(serialized_user, user_1)
def test_it_returns_user_preferences(
self, app: Flask, user_1: User
) -> None:
serialized_user = user_1.serialize(user_1)
assert serialized_user['imperial_units'] == user_1.imperial_units
assert serialized_user['language'] == user_1.language
assert serialized_user['timezone'] == user_1.timezone
assert serialized_user['weekm'] == user_1.weekm
def test_it_returns_workouts_infos(self, app: Flask, user_1: User) -> None:
serialized_user = user_1.serialize(user_1)
self.assert_workouts_keys_are_present(serialized_user)
def test_it_does_not_return_confirmation_token(
self, app: Flask, user_1_admin: User, user_2: User
) -> None:
serialized_user = user_2.serialize(user_1_admin)
assert 'confirmation_token' not in serialized_user
class TestUserSerializeAsAdmin(UserModelAssertMixin):
def test_it_returns_user_account_infos(
self, app: Flask, user_1_admin: User, user_2: User
) -> None:
serialized_user = user_2.serialize(user_1_admin)
self.assert_user_account(serialized_user, user_2)
def test_it_returns_user_profile_infos(
self, app: Flask, user_1_admin: User, user_2: User
) -> None:
serialized_user = user_2.serialize(user_1_admin)
self.assert_user_profile(serialized_user, user_1_admin)
def test_it_does_return_user_preferences(
self, app: Flask, user_1_admin: User, user_2: User self, app: Flask, user_1_admin: User, user_2: User
) -> None: ) -> None:
serialized_user = user_2.serialize(user_1_admin) serialized_user = user_2.serialize(user_1_admin)
self.assert_serialized_used(serialized_user)
assert 'toto' == serialized_user['username']
assert 'toto@toto.com' == serialized_user['email']
assert serialized_user['nb_sports'] == 0
assert serialized_user['records'] == []
assert serialized_user['sports_list'] == []
assert serialized_user['total_distance'] == 0
assert serialized_user['total_duration'] == '0:00:00'
assert serialized_user['email_to_confirm'] is None
assert 'imperial_units' not in serialized_user assert 'imperial_units' not in serialized_user
assert 'language' not in serialized_user assert 'language' not in serialized_user
assert 'timezone' not in serialized_user assert 'timezone' not in serialized_user
assert 'weekm' not in serialized_user assert 'weekm' not in serialized_user
def test_it_returns_workouts_infos(
self, app: Flask, user_1_admin: User, user_2: User
) -> None:
serialized_user = user_2.serialize(user_1_admin)
self.assert_workouts_keys_are_present(serialized_user)
def test_it_does_not_return_confirmation_token(
self, app: Flask, user_1_admin: User, user_2: User
) -> None:
serialized_user = user_2.serialize(user_1_admin)
assert 'confirmation_token' not in serialized_user assert 'confirmation_token' not in serialized_user
class TestInactiveUserSerialize(UserModelAssertMixin):
def test_it_returns_is_active_to_false_for_inactive_user(
self,
app: Flask,
inactive_user: User,
) -> None:
serialized_user = inactive_user.serialize(inactive_user)
assert serialized_user['is_active'] is False
class TestUserSerializeAsRegularUser(UserModelAssertMixin):
def test_user_model_as_regular_user( def test_user_model_as_regular_user(
self, app: Flask, user_1: User, user_2: User self, app: Flask, user_1: User, user_2: User
) -> None: ) -> None:
with pytest.raises(UserNotFoundException): with pytest.raises(UserNotFoundException):
user_2.serialize(user_1) user_2.serialize(user_1)
def test_encode_auth_token(self, app: Flask, user_1: User) -> None:
auth_token = user_1.encode_auth_token(user_1.id)
assert isinstance(auth_token, str)
def test_encode_password_token(self, app: Flask, user_1: User) -> None: class TestUserRecords(UserModelAssertMixin):
password_token = user_1.encode_password_reset_token(user_1.id) def test_it_returns_empty_list_when_no_workouts(
assert isinstance(password_token, str) self,
app: Flask,
user_1: User,
) -> None:
serialized_user = user_1.serialize(user_1)
def test_decode_auth_token(self, app: Flask, user_1: User) -> None: assert serialized_user['records'] == []
auth_token = user_1.encode_auth_token(user_1.id)
assert isinstance(auth_token, str)
assert User.decode_auth_token(auth_token) == user_1.id
def test_it_returns_user_records( def test_it_returns_user_records(
self, self,
@ -100,14 +168,79 @@ class TestUserModel:
) )
assert serialized_user['records'][0]['workout_date'] assert serialized_user['records'][0]['workout_date']
def test_it_returns_is_active_to_false_fot_inactive_user(
class TestUserWorkouts(UserModelAssertMixin):
def test_it_returns_infos_when_no_workouts(
self, self,
app: Flask, app: Flask,
inactive_user: User, user_1: User,
) -> None: ) -> None:
serialized_user = inactive_user.serialize(inactive_user) serialized_user = user_1.serialize(user_1)
assert serialized_user['is_active'] is False assert serialized_user['nb_sports'] == 0
assert serialized_user['nb_workouts'] == 0
assert serialized_user['sports_list'] == []
assert serialized_user['total_distance'] == 0
assert serialized_user['total_duration'] == '0:00:00'
def test_it_returns_infos_when_only_one_workout_exists(
self,
app: Flask,
user_1: User,
sport_1_cycling: Sport,
workout_cycling_user_1: Workout,
) -> None:
serialized_user = user_1.serialize(user_1)
assert serialized_user['nb_sports'] == 1
assert serialized_user['nb_workouts'] == 1
assert serialized_user['sports_list'] == [sport_1_cycling.id]
assert (
serialized_user['total_distance']
== workout_cycling_user_1.distance
)
assert serialized_user['total_duration'] == str(
workout_cycling_user_1.duration
)
def test_it_returns_infos_when_several_sports(
self,
app: Flask,
user_1: User,
sport_1_cycling: Sport,
sport_2_running: Sport,
workout_cycling_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
serialized_user = user_1.serialize(user_1)
assert serialized_user['nb_sports'] == 2
assert serialized_user['nb_workouts'] == 2
assert serialized_user['sports_list'] == [
sport_1_cycling.id,
sport_2_running.id,
]
assert serialized_user['total_distance'] == (
workout_cycling_user_1.distance + workout_running_user_1.distance
)
assert serialized_user['total_duration'] == str(
workout_cycling_user_1.duration + workout_running_user_1.duration
)
class TestUserModelToken:
def test_encode_auth_token(self, app: Flask, user_1: User) -> None:
auth_token = user_1.encode_auth_token(user_1.id)
assert isinstance(auth_token, str)
def test_encode_password_token(self, app: Flask, user_1: User) -> None:
password_token = user_1.encode_password_reset_token(user_1.id)
assert isinstance(password_token, str)
def test_decode_auth_token(self, app: Flask, user_1: User) -> None:
auth_token = user_1.encode_auth_token(user_1.id)
assert isinstance(auth_token, str)
assert User.decode_auth_token(auth_token) == user_1.id
class TestUserSportModel: class TestUserSportModel:

View File

@ -1,6 +1,9 @@
import random import random
import string import string
from typing import Optional from json import loads
from typing import Dict, Optional
from flask import json as flask_json
def random_string( def random_string(
@ -23,3 +26,7 @@ def random_string(
def random_email() -> str: def random_email() -> str:
return random_string(suffix='@example.com') return random_string(suffix='@example.com')
def jsonify_dict(data: Dict) -> Dict:
return loads(flask_json.dumps(data))

View File

@ -14,26 +14,34 @@ class TestRecordModel:
sport_1_cycling: Sport, sport_1_cycling: Sport,
workout_cycling_user_1: Workout, workout_cycling_user_1: Workout,
) -> None: ) -> None:
record_type = 'LD'
record_ld = Record.query.filter_by( record_ld = Record.query.filter_by(
user_id=workout_cycling_user_1.user_id, user_id=workout_cycling_user_1.user_id,
sport_id=workout_cycling_user_1.sport_id, sport_id=workout_cycling_user_1.sport_id,
record_type='LD', record_type=record_type,
).first() ).first()
assert 'test' == record_ld.user.username
assert 1 == record_ld.sport_id assert record_ld.user.username == user_1.username
assert 1 == record_ld.workout_id assert record_ld.sport_id == sport_1_cycling.id
assert 'LD' == record_ld.record_type assert record_ld.workout_id == workout_cycling_user_1.sport_id
assert '2018-01-01 00:00:00' == str(record_ld.workout_date) assert record_ld.record_type == record_type
assert str(record_ld.workout_date) == str(
workout_cycling_user_1.workout_date
)
assert record_ld.value == workout_cycling_user_1.duration
assert '<Record Cycling - LD - 2018-01-01>' == str(record_ld) assert '<Record Cycling - LD - 2018-01-01>' == str(record_ld)
record_serialize = record_ld.serialize() record_serialize = record_ld.serialize()
assert 'id' in record_serialize
assert 'user' in record_serialize record_serialize['id'] = record_ld.id
assert 'sport_id' in record_serialize record_serialize['record_type'] = record_ld.record_type
assert 'workout_id' in record_serialize record_serialize['sport_id'] = record_ld.sport_id
assert 'record_type' in record_serialize record_serialize['user'] = record_ld.user.username
assert 'workout_date' in record_serialize record_serialize['value'] = record_ld.value
assert 'value' in record_serialize record_serialize['workout_id'] = record_ld.workout_id
record_serialize['workout_date'] = record_ld.workout_date
def test_record_model_with_none_value( def test_record_model_with_none_value(
self, self,
@ -48,12 +56,7 @@ class TestRecordModel:
record_type='LD', record_type='LD',
).first() ).first()
record_ld.value = None record_ld.value = None
assert 'test' == record_ld.user.username
assert 1 == record_ld.sport_id
assert 1 == record_ld.workout_id
assert 'LD' == record_ld.record_type
assert '2018-01-01 00:00:00' == str(record_ld.workout_date)
assert '<Record Cycling - LD - 2018-01-01>' == str(record_ld)
assert record_ld.value is None assert record_ld.value is None
record_serialize = record_ld.serialize() record_serialize = record_ld.serialize()
@ -80,7 +83,7 @@ class TestRecordModel:
assert record_serialize.get('value') == 10.0 assert record_serialize.get('value') == 10.0
assert isinstance(record_serialize.get('value'), float) assert isinstance(record_serialize.get('value'), float)
def test_add_farest_distance_records( def test_add_farthest_distance_records(
self, self,
app: Flask, app: Flask,
user_1: User, user_1: User,

View File

@ -7,41 +7,7 @@ from fittrackee.users.models import User, UserSportPreference
from fittrackee.workouts.models import Sport, Workout from fittrackee.workouts.models import Sport, Workout
from ..mixins import ApiTestCaseMixin from ..mixins import ApiTestCaseMixin
from ..utils import jsonify_dict
expected_sport_1_cycling_result = {
'id': 1,
'label': 'Cycling',
'is_active': True,
'is_active_for_user': True,
'color': None,
'stopped_speed_threshold': 1,
}
expected_sport_1_cycling_admin_result = expected_sport_1_cycling_result.copy()
expected_sport_1_cycling_admin_result['has_workouts'] = False
expected_sport_2_running_result = {
'id': 2,
'label': 'Running',
'is_active': True,
'is_active_for_user': True,
'color': None,
'stopped_speed_threshold': 0.1,
}
expected_sport_2_running_admin_result = expected_sport_2_running_result.copy()
expected_sport_2_running_admin_result['has_workouts'] = False
expected_sport_1_cycling_inactive_result = {
'id': 1,
'label': 'Cycling',
'is_active': False,
'is_active_for_user': False,
'color': None,
'stopped_speed_threshold': 1,
}
expected_sport_1_cycling_inactive_admin_result = (
expected_sport_1_cycling_inactive_result.copy()
)
expected_sport_1_cycling_inactive_admin_result['has_workouts'] = False
class TestGetSports(ApiTestCaseMixin): class TestGetSports(ApiTestCaseMixin):
@ -75,8 +41,12 @@ class TestGetSports(ApiTestCaseMixin):
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']) == 2 assert len(data['data']['sports']) == 2
assert data['data']['sports'][0] == expected_sport_1_cycling_result assert data['data']['sports'][0] == jsonify_dict(
assert data['data']['sports'][1] == expected_sport_2_running_result sport_1_cycling.serialize()
)
assert data['data']['sports'][1] == jsonify_dict(
sport_2_running.serialize()
)
def test_it_gets_all_sports_with_inactive_one( def test_it_gets_all_sports_with_inactive_one(
self, self,
@ -98,11 +68,12 @@ class TestGetSports(ApiTestCaseMixin):
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']) == 2 assert len(data['data']['sports']) == 2
assert ( assert data['data']['sports'][0] == jsonify_dict(
data['data']['sports'][0] sport_1_cycling_inactive.serialize()
== expected_sport_1_cycling_inactive_result )
assert data['data']['sports'][1] == jsonify_dict(
sport_2_running.serialize()
) )
assert data['data']['sports'][1] == expected_sport_2_running_result
def test_it_gets_all_sports_with_admin_rights( def test_it_gets_all_sports_with_admin_rights(
self, self,
@ -124,12 +95,11 @@ class TestGetSports(ApiTestCaseMixin):
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']) == 2 assert len(data['data']['sports']) == 2
assert ( assert data['data']['sports'][0] == jsonify_dict(
data['data']['sports'][0] sport_1_cycling_inactive.serialize(is_admin=True)
== expected_sport_1_cycling_inactive_admin_result
) )
assert ( assert data['data']['sports'][1] == jsonify_dict(
data['data']['sports'][1] == expected_sport_2_running_admin_result sport_2_running.serialize(is_admin=True)
) )
def test_it_gets_sports_with_auth_user_preferences( def test_it_gets_sports_with_auth_user_preferences(
@ -158,11 +128,14 @@ class TestGetSports(ApiTestCaseMixin):
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']) == 2 assert len(data['data']['sports']) == 2
assert data['data']['sports'][0]['color'] == '#000000' assert data['data']['sports'][0] == jsonify_dict(
assert data['data']['sports'][0]['stopped_speed_threshold'] == 0.5 sport_1_cycling.serialize(
assert data['data']['sports'][0]['is_active_for_user'] is False is_admin=True,
assert ( sport_preferences=user_admin_sport_1_preference.serialize(),
data['data']['sports'][1] == expected_sport_2_running_admin_result )
)
assert data['data']['sports'][1] == jsonify_dict(
sport_2_running.serialize(is_admin=True)
) )
@ -183,7 +156,9 @@ class TestGetSport(ApiTestCaseMixin):
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 data['data']['sports'][0] == expected_sport_1_cycling_result assert data['data']['sports'][0] == jsonify_dict(
sport_1_cycling.serialize()
)
def test_it_gets_a_sport_with_preferences( def test_it_gets_a_sport_with_preferences(
self, self,
@ -205,7 +180,11 @@ class TestGetSport(ApiTestCaseMixin):
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 data['data']['sports'][0] == expected_sport_1_cycling_result assert data['data']['sports'][0] == jsonify_dict(
sport_1_cycling.serialize(
sport_preferences=user_sport_1_preference.serialize()
)
)
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
@ -238,9 +217,8 @@ class TestGetSport(ApiTestCaseMixin):
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] == jsonify_dict(
data['data']['sports'][0] sport_1_cycling_inactive.serialize()
== expected_sport_1_cycling_inactive_result
) )
def test_it_get_an_inactive_sport_with_admin_rights( def test_it_get_an_inactive_sport_with_admin_rights(
@ -259,9 +237,8 @@ class TestGetSport(ApiTestCaseMixin):
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] == jsonify_dict(
data['data']['sports'][0] sport_1_cycling_inactive.serialize(is_admin=True)
== expected_sport_1_cycling_inactive_admin_result
) )
@ -388,7 +365,6 @@ class TestUpdateSport(ApiTestCaseMixin):
assert len(data['data']['sports']) == 1 assert len(data['data']['sports']) == 1
assert data['data']['sports'][0]['is_active'] is False assert data['data']['sports'][0]['is_active'] is False
assert data['data']['sports'][0]['is_active_for_user'] is False assert data['data']['sports'][0]['is_active_for_user'] is False
assert data['data']['sports'][0]['is_active_for_user'] is False
assert data['data']['sports'][0]['has_workouts'] is False assert data['data']['sports'][0]['has_workouts'] is False
def test_it_enables_a_sport_with_preferences( def test_it_enables_a_sport_with_preferences(

View File

@ -17,15 +17,17 @@ class TestSportModel:
assert '<Sport \'Cycling\'>' == str(sport) assert '<Sport \'Cycling\'>' == str(sport)
serialized_sport = sport.serialize(is_admin=is_admin) serialized_sport = sport.serialize(is_admin=is_admin)
assert 1 == serialized_sport['id'] assert serialized_sport['label'] == sport.label
assert 'Cycling' == serialized_sport['label'] assert serialized_sport['id'] == sport.id
assert serialized_sport['is_active'] is True assert serialized_sport['is_active'] is True
assert serialized_sport['is_active_for_user'] is True assert serialized_sport['is_active_for_user'] is True
assert serialized_sport['color'] is None assert serialized_sport['color'] is None
assert serialized_sport['stopped_speed_threshold'] == 1 assert serialized_sport['stopped_speed_threshold'] == 1
return serialized_sport return serialized_sport
def test_sport_model(self, app: Flask, sport_1_cycling: Sport) -> None: def test_sport_model_without_workout(
self, app: Flask, sport_1_cycling: Sport
) -> None:
serialized_sport = self.assert_sport_model(sport_1_cycling) serialized_sport = self.assert_sport_model(sport_1_cycling)
assert 'has_workouts' not in serialized_sport assert 'has_workouts' not in serialized_sport

View File

@ -1,4 +1,5 @@
import json import json
from typing import List
from unittest.mock import patch from unittest.mock import patch
from uuid import uuid4 from uuid import uuid4
@ -8,6 +9,7 @@ from fittrackee.users.models import User
from fittrackee.workouts.models import Sport, Workout from fittrackee.workouts.models import Sport, Workout
from ..mixins import ApiTestCaseMixin from ..mixins import ApiTestCaseMixin
from ..utils import jsonify_dict
from .utils import get_random_short_id from .utils import get_random_short_id
@ -45,25 +47,12 @@ class TestGetWorkouts(ApiTestCaseMixin):
assert response.status_code == 200 assert response.status_code == 200
assert 'success' in data['status'] assert 'success' in data['status']
assert len(data['data']['workouts']) == 2 assert len(data['data']['workouts']) == 2
assert 'creation_date' in data['data']['workouts'][0] assert data['data']['workouts'][0] == jsonify_dict(
assert ( workout_running_user_1.serialize()
'Sun, 01 Apr 2018 00:00:00 GMT'
== data['data']['workouts'][0]['workout_date']
) )
assert 'test' == data['data']['workouts'][0]['user'] assert data['data']['workouts'][1] == jsonify_dict(
assert 2 == data['data']['workouts'][0]['sport_id'] workout_cycling_user_1.serialize()
assert 12.0 == data['data']['workouts'][0]['distance']
assert '1:40:00' == data['data']['workouts'][0]['duration']
assert 'creation_date' in data['data']['workouts'][1]
assert (
'Mon, 01 Jan 2018 00:00:00 GMT'
== data['data']['workouts'][1]['workout_date']
) )
assert 'test' == data['data']['workouts'][1]['user']
assert 1 == data['data']['workouts'][1]['sport_id']
assert 10.0 == data['data']['workouts'][1]['distance']
assert '1:00:00' == data['data']['workouts'][1]['duration']
assert data['pagination'] == { assert data['pagination'] == {
'has_next': False, 'has_next': False,
'has_prev': False, 'has_prev': False,
@ -119,7 +108,7 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -134,18 +123,22 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin):
assert response.status_code == 200 assert response.status_code == 200
assert 'success' in data['status'] assert 'success' in data['status']
assert len(data['data']['workouts']) == 5 assert len(data['data']['workouts']) == 5
assert 'creation_date' in data['data']['workouts'][0] assert data['data']['workouts'][0] == jsonify_dict(
assert ( seven_workouts_user_1[6].serialize()
'Wed, 09 May 2018 00:00:00 GMT'
== data['data']['workouts'][0]['workout_date']
) )
assert '0:50:00' == data['data']['workouts'][0]['duration'] assert data['data']['workouts'][1] == jsonify_dict(
assert 'creation_date' in data['data']['workouts'][4] seven_workouts_user_1[5].serialize()
assert (
'Mon, 01 Jan 2018 00:00:00 GMT'
== data['data']['workouts'][4]['workout_date']
) )
assert '0:17:04' == data['data']['workouts'][4]['duration'] assert data['data']['workouts'][2] == jsonify_dict(
seven_workouts_user_1[3].serialize()
)
assert data['data']['workouts'][3] == jsonify_dict(
seven_workouts_user_1[4].serialize()
)
assert data['data']['workouts'][4] == jsonify_dict(
seven_workouts_user_1[2].serialize()
)
assert data['pagination'] == { assert data['pagination'] == {
'has_next': True, 'has_next': True,
'has_prev': False, 'has_prev': False,
@ -159,7 +152,7 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -174,18 +167,21 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin):
assert response.status_code == 200 assert response.status_code == 200
assert 'success' in data['status'] assert 'success' in data['status']
assert len(data['data']['workouts']) == 5 assert len(data['data']['workouts']) == 5
assert 'creation_date' in data['data']['workouts'][0] assert data['data']['workouts'][0] == jsonify_dict(
assert ( seven_workouts_user_1[6].serialize()
'Wed, 09 May 2018 00:00:00 GMT'
== data['data']['workouts'][0]['workout_date']
) )
assert '0:50:00' == data['data']['workouts'][0]['duration'] assert data['data']['workouts'][1] == jsonify_dict(
assert 'creation_date' in data['data']['workouts'][4] seven_workouts_user_1[5].serialize()
assert ( )
'Mon, 01 Jan 2018 00:00:00 GMT' assert data['data']['workouts'][2] == jsonify_dict(
== data['data']['workouts'][4]['workout_date'] seven_workouts_user_1[3].serialize()
)
assert data['data']['workouts'][3] == jsonify_dict(
seven_workouts_user_1[4].serialize()
)
assert data['data']['workouts'][4] == jsonify_dict(
seven_workouts_user_1[2].serialize()
) )
assert '0:17:04' == data['data']['workouts'][4]['duration']
assert data['pagination'] == { assert data['pagination'] == {
'has_next': True, 'has_next': True,
'has_prev': False, 'has_prev': False,
@ -199,7 +195,7 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -214,18 +210,12 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin):
assert response.status_code == 200 assert response.status_code == 200
assert 'success' in data['status'] assert 'success' in data['status']
assert len(data['data']['workouts']) == 2 assert len(data['data']['workouts']) == 2
assert 'creation_date' in data['data']['workouts'][0] assert data['data']['workouts'][0] == jsonify_dict(
assert ( seven_workouts_user_1[1].serialize()
'Thu, 01 Jun 2017 00:00:00 GMT'
== data['data']['workouts'][0]['workout_date']
) )
assert '0:57:36' == data['data']['workouts'][0]['duration'] assert data['data']['workouts'][1] == jsonify_dict(
assert 'creation_date' in data['data']['workouts'][1] seven_workouts_user_1[0].serialize()
assert (
'Mon, 20 Mar 2017 00:00:00 GMT'
== data['data']['workouts'][1]['workout_date']
) )
assert '0:17:04' == data['data']['workouts'][1]['duration']
assert data['pagination'] == { assert data['pagination'] == {
'has_next': False, 'has_next': False,
'has_prev': True, 'has_prev': True,
@ -239,7 +229,7 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -267,7 +257,7 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -286,7 +276,7 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -301,13 +291,11 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin):
assert response.status_code == 200 assert response.status_code == 200
assert 'success' in data['status'] assert 'success' in data['status']
assert len(data['data']['workouts']) == 6 assert len(data['data']['workouts']) == 6
assert ( assert data['data']['workouts'][0] == jsonify_dict(
'Wed, 09 May 2018 00:00:00 GMT' seven_workouts_user_1[6].serialize()
== data['data']['workouts'][0]['workout_date']
) )
assert ( assert data['data']['workouts'][5] == jsonify_dict(
'Thu, 01 Jun 2017 00:00:00 GMT' seven_workouts_user_1[1].serialize()
== data['data']['workouts'][5]['workout_date']
) )
assert data['pagination'] == { assert data['pagination'] == {
'has_next': True, 'has_next': True,
@ -323,7 +311,7 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -338,13 +326,14 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin):
assert response.status_code == 200 assert response.status_code == 200
assert 'success' in data['status'] assert 'success' in data['status']
assert len(data['data']['workouts']) == 3 assert len(data['data']['workouts']) == 3
assert ( assert data['data']['workouts'][0] == jsonify_dict(
'Wed, 09 May 2018 00:00:00 GMT' seven_workouts_user_1[6].serialize()
== data['data']['workouts'][0]['workout_date']
) )
assert ( assert data['data']['workouts'][1] == jsonify_dict(
'Fri, 23 Feb 2018 00:00:00 GMT' seven_workouts_user_1[5].serialize()
== data['data']['workouts'][2]['workout_date'] )
assert data['data']['workouts'][2] == jsonify_dict(
seven_workouts_user_1[4].serialize()
) )
assert data['pagination'] == { assert data['pagination'] == {
'has_next': True, 'has_next': True,
@ -361,7 +350,7 @@ class TestGetWorkoutsWithOrder(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -397,7 +386,7 @@ class TestGetWorkoutsWithOrder(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -433,7 +422,7 @@ class TestGetWorkoutsWithOrder(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -471,7 +460,7 @@ class TestGetWorkoutsWithOrderBy(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -507,7 +496,7 @@ class TestGetWorkoutsWithOrderBy(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -537,7 +526,7 @@ class TestGetWorkoutsWithOrderBy(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -567,7 +556,7 @@ class TestGetWorkoutsWithOrderBy(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -599,7 +588,7 @@ class TestGetWorkoutsWithFilters(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -625,7 +614,6 @@ class TestGetWorkoutsWithFilters(ApiTestCaseMixin):
'Fri, 23 Feb 2018 00:00:00 GMT' 'Fri, 23 Feb 2018 00:00:00 GMT'
== data['data']['workouts'][1]['workout_date'] == data['data']['workouts'][1]['workout_date']
) )
assert '0:10:00' == data['data']['workouts'][1]['duration']
assert data['pagination'] == { assert data['pagination'] == {
'has_next': False, 'has_next': False,
'has_prev': False, 'has_prev': False,
@ -639,7 +627,7 @@ class TestGetWorkoutsWithFilters(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -667,7 +655,7 @@ class TestGetWorkoutsWithFilters(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -704,7 +692,7 @@ class TestGetWorkoutsWithFilters(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -740,7 +728,7 @@ class TestGetWorkoutsWithFilters(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -776,7 +764,7 @@ class TestGetWorkoutsWithFilters(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -808,7 +796,7 @@ class TestGetWorkoutsWithFilters(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -876,7 +864,7 @@ class TestGetWorkoutsWithFilters(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
sport_2_running: Sport, sport_2_running: Sport,
workout_running_user_1: Workout, workout_running_user_1: Workout,
) -> None: ) -> None:
@ -912,7 +900,7 @@ class TestGetWorkoutsWithFiltersAndPagination(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -948,7 +936,7 @@ class TestGetWorkoutsWithFiltersAndPagination(ApiTestCaseMixin):
app: Flask, app: Flask,
user_1: User, user_1: User,
sport_1_cycling: Sport, sport_1_cycling: Sport,
seven_workouts_user_1: Workout, seven_workouts_user_1: List[Workout],
) -> None: ) -> None:
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
@ -1001,15 +989,9 @@ class TestGetWorkout(ApiTestCaseMixin):
assert response.status_code == 200 assert response.status_code == 200
assert 'success' in data['status'] assert 'success' in data['status']
assert len(data['data']['workouts']) == 1 assert len(data['data']['workouts']) == 1
assert 'creation_date' in data['data']['workouts'][0] assert data['data']['workouts'][0] == jsonify_dict(
assert ( workout_cycling_user_1.serialize()
'Mon, 01 Jan 2018 00:00:00 GMT'
== data['data']['workouts'][0]['workout_date']
) )
assert 'test' == data['data']['workouts'][0]['user']
assert 1 == data['data']['workouts'][0]['sport_id']
assert 10.0 == data['data']['workouts'][0]['distance']
assert '1:00:00' == data['data']['workouts'][0]['duration']
def test_it_returns_403_if_workout_belongs_to_a_different_user( def test_it_returns_403_if_workout_belongs_to_a_different_user(
self, self,

View File

@ -1,15 +1,17 @@
from uuid import UUID from datetime import timedelta
from flask import Flask from flask import Flask
from fittrackee import db from fittrackee import db
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 fittrackee.workouts.utils.short_id import decode_short_id from fittrackee.workouts.utils.short_id import encode_uuid
from ..utils import random_string
class TestWorkoutModel: class TestWorkoutModel:
def test_workout_model( def test_sport_label_and_date_are_in_string_value(
self, self,
app: Flask, app: Flask,
sport_1_cycling: Sport, sport_1_cycling: Sport,
@ -18,48 +20,109 @@ class TestWorkoutModel:
) -> None: ) -> None:
workout_cycling_user_1.title = 'Test' workout_cycling_user_1.title = 'Test'
db.session.commit() db.session.commit()
assert 1 == workout_cycling_user_1.id
assert workout_cycling_user_1.uuid is not None
assert 1 == workout_cycling_user_1.user_id
assert 1 == workout_cycling_user_1.sport_id
assert '2018-01-01 00:00:00' == str(
workout_cycling_user_1.workout_date
)
assert 10.0 == float(workout_cycling_user_1.distance)
assert '1:00:00' == str(workout_cycling_user_1.duration)
assert 'Test' == workout_cycling_user_1.title
assert '<Workout \'Cycling\' - 2018-01-01 00:00:00>' == str( assert '<Workout \'Cycling\' - 2018-01-01 00:00:00>' == str(
workout_cycling_user_1 workout_cycling_user_1
) )
serialized_workout = workout_cycling_user_1.serialize() def test_short_id_returns_encoded_workout_uuid(
assert isinstance(decode_short_id(serialized_workout['id']), UUID) self,
assert 'test' == serialized_workout['user'] app: Flask,
assert 1 == serialized_workout['sport_id'] sport_1_cycling: Sport,
assert serialized_workout['title'] == 'Test' user_1: User,
assert 'creation_date' in serialized_workout workout_cycling_user_1: Workout,
assert serialized_workout['modification_date'] is not None ) -> None:
assert str(serialized_workout['workout_date']) == '2018-01-01 00:00:00' assert workout_cycling_user_1.short_id == encode_uuid(
assert serialized_workout['duration'] == '1:00:00' workout_cycling_user_1.uuid
assert serialized_workout['pauses'] is None )
assert serialized_workout['moving'] == '1:00:00'
assert serialized_workout['distance'] == 10.0 def test_serialize_for_workout_without_gpx(
assert serialized_workout['max_alt'] is None self,
assert serialized_workout['descent'] is None app: Flask,
sport_1_cycling: Sport,
user_1: User,
workout_cycling_user_1: Workout,
) -> None:
workout = workout_cycling_user_1
serialized_workout = workout.serialize()
assert serialized_workout['ascent'] is None assert serialized_workout['ascent'] is None
assert serialized_workout['max_speed'] == 10.0 assert serialized_workout['ave_speed'] == float(workout.ave_speed)
assert serialized_workout['ave_speed'] == 10.0
assert serialized_workout['with_gpx'] is False
assert serialized_workout['bounds'] == [] assert serialized_workout['bounds'] == []
assert serialized_workout['previous_workout'] is None assert 'creation_date' in serialized_workout
assert serialized_workout['next_workout'] is None assert serialized_workout['descent'] is None
assert serialized_workout['segments'] == [] assert serialized_workout['distance'] == float(workout.distance)
assert serialized_workout['records'] != [] assert serialized_workout['duration'] == str(workout.duration)
assert serialized_workout['id'] == workout.short_id
assert serialized_workout['map'] is None assert serialized_workout['map'] is None
assert serialized_workout['weather_start'] is None assert serialized_workout['max_alt'] is None
assert serialized_workout['weather_end'] is None assert serialized_workout['max_speed'] == float(workout.max_speed)
assert serialized_workout['min_alt'] is None
assert serialized_workout['modification_date'] is None
assert serialized_workout['moving'] == str(workout.moving)
assert serialized_workout['next_workout'] is None
assert serialized_workout['notes'] is None assert serialized_workout['notes'] is None
assert serialized_workout['pauses'] is None
assert serialized_workout['previous_workout'] is None
assert serialized_workout['records'] == [
record.serialize() for record in workout.records
]
assert serialized_workout['segments'] == []
assert serialized_workout['sport_id'] == workout.sport_id
assert serialized_workout['title'] == workout.title
assert serialized_workout['user'] == workout.user.username
assert serialized_workout['weather_end'] is None
assert serialized_workout['weather_start'] is None
assert serialized_workout['with_gpx'] is False
assert str(serialized_workout['workout_date']) == '2018-01-01 00:00:00'
def test_serialize_for_workout_with_gpx(
self,
app: Flask,
sport_1_cycling: Sport,
user_1: User,
workout_cycling_user_1: Workout,
workout_cycling_user_1_segment: Workout,
) -> None:
workout = workout_cycling_user_1
workout.bounds = [1, 2, 3, 4]
workout.gpx = random_string()
workout.map = random_string()
workout.pauses = timedelta(minutes=15)
serialized_workout = workout.serialize()
assert serialized_workout['ascent'] is None
assert serialized_workout['ave_speed'] == float(workout.ave_speed)
assert serialized_workout['bounds'] == [
float(bound) for bound in workout.bounds
]
assert 'creation_date' in serialized_workout
assert serialized_workout['descent'] is None
assert serialized_workout['distance'] == float(workout.distance)
assert serialized_workout['duration'] == str(workout.duration)
assert serialized_workout['id'] == workout.short_id
assert serialized_workout['map'] is None
assert serialized_workout['max_alt'] is None
assert serialized_workout['max_speed'] == float(workout.max_speed)
assert serialized_workout['min_alt'] is None
assert serialized_workout['modification_date'] is not None
assert serialized_workout['moving'] == str(workout.moving)
assert serialized_workout['next_workout'] is None
assert serialized_workout['notes'] is None
assert serialized_workout['pauses'] == str(workout.pauses)
assert serialized_workout['previous_workout'] is None
assert serialized_workout['records'] == [
record.serialize() for record in workout.records
]
assert serialized_workout['segments'] == [
segment.serialize() for segment in workout.segments
]
assert serialized_workout['sport_id'] == workout.sport_id
assert serialized_workout['title'] == workout.title
assert serialized_workout['user'] == workout.user.username
assert serialized_workout['weather_end'] is None
assert serialized_workout['weather_start'] is None
assert serialized_workout['with_gpx'] is True
assert str(serialized_workout['workout_date']) == '2018-01-01 00:00:00'
def test_workout_segment_model( def test_workout_segment_model(
self, self,
@ -74,3 +137,35 @@ class TestWorkoutModel:
f'for workout \'{workout_cycling_user_1.short_id}\'>' f'for workout \'{workout_cycling_user_1.short_id}\'>'
== str(workout_cycling_user_1_segment) == str(workout_cycling_user_1_segment)
) )
def test_it_returns_previous_workout(
self,
app: Flask,
sport_1_cycling: Sport,
sport_2_running: Sport,
user_1: User,
workout_cycling_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
serialized_workout = workout_running_user_1.serialize()
assert (
serialized_workout['previous_workout']
== workout_cycling_user_1.short_id
)
def test_it_returns_next_workout(
self,
app: Flask,
sport_1_cycling: Sport,
sport_2_running: Sport,
user_1: User,
workout_cycling_user_1: Workout,
workout_running_user_1: Workout,
) -> None:
serialized_workout = workout_cycling_user_1.serialize()
assert (
serialized_workout['next_workout']
== workout_running_user_1.short_id
)

View File

@ -791,8 +791,9 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
} }
:<json string timezone: user time zone :<json string timezone: user time zone
:<json string weekm: does week start on Monday? :<json boolean weekm: does week start on Monday?
:<json string language: language preferences :<json string language: language preferences
:<json boolean imperial_units: display distance in imperial units
:reqheader Authorization: OAuth 2.0 Bearer Token :reqheader Authorization: OAuth 2.0 Bearer Token

View File

@ -249,12 +249,13 @@ def get_users(auth_user: User) -> Dict:
@users_blueprint.route('/users/<user_name>', methods=['GET']) @users_blueprint.route('/users/<user_name>', methods=['GET'])
@authenticate_as_admin @authenticate
def get_single_user( def get_single_user(
auth_user: User, user_name: str auth_user: User, user_name: str
) -> Union[Dict, HttpResponse]: ) -> Union[Dict, HttpResponse]:
""" """
Get single user details. Only user with admin rights can get user details. Get single user details. Only user with admin rights can get other users
details.
It returns user preferences only for authenticated user. It returns user preferences only for authenticated user.
@ -353,6 +354,9 @@ def get_single_user(
:statuscode 404: :statuscode 404:
- user does not exist - user does not exist
""" """
if user_name != auth_user.username and not auth_user.admin:
return ForbiddenErrorResponse()
try: try:
user = User.query.filter_by(username=user_name).first() user = User.query.filter_by(username=user_name).first()
if user: if user:

View File

@ -1,6 +1,6 @@
{ {
"name": "fittrackee_client", "name": "fittrackee_client",
"version": "0.6.1", "version": "0.6.2",
"private": true, "private": true,
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",
@ -22,7 +22,7 @@
"chartjs-plugin-datalabels": "^2.0.0", "chartjs-plugin-datalabels": "^2.0.0",
"core-js": "^3.21.1", "core-js": "^3.21.1",
"date-fns": "^2.28.0", "date-fns": "^2.28.0",
"date-fns-tz": "^1.3.1", "date-fns-tz": "^1.3.3",
"leaflet": "^1.7.1", "leaflet": "^1.7.1",
"register-service-worker": "^1.7.1", "register-service-worker": "^1.7.1",
"vue": "^3.0.0", "vue": "^3.0.0",
@ -36,8 +36,8 @@
"@intlify/vue-i18n-loader": "^4.0.1", "@intlify/vue-i18n-loader": "^4.0.1",
"@types/chai": "^4.2.11", "@types/chai": "^4.2.11",
"@types/mocha": "^9.1.0", "@types/mocha": "^9.1.0",
"@typescript-eslint/eslint-plugin": "^5.4.0", "@typescript-eslint/eslint-plugin": "^5.17.0",
"@typescript-eslint/parser": "^5.4.0", "@typescript-eslint/parser": "^5.17.0",
"@vue/cli-plugin-babel": "~5.0.1", "@vue/cli-plugin-babel": "~5.0.1",
"@vue/cli-plugin-eslint": "~5.0.1", "@vue/cli-plugin-eslint": "~5.0.1",
"@vue/cli-plugin-pwa": "~5.0.1", "@vue/cli-plugin-pwa": "~5.0.1",
@ -51,14 +51,14 @@
"chai": "^4.3.6", "chai": "^4.3.6",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-typescript": "^2.7.0", "eslint-import-resolver-typescript": "^2.7.1",
"eslint-plugin-import": "^2.24.1", "eslint-plugin-import": "^2.24.1",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.5.0", "eslint-plugin-vue": "^8.5.0",
"prettier": "^2.6.1", "prettier": "^2.6.2",
"sass": "^1.49.9", "sass": "^1.49.11",
"sass-loader": "^12.6.0", "sass-loader": "^12.6.0",
"typescript": "~4.5.5", "typescript": "^4.6.3",
"vue-cli-plugin-i18n": "~2.3.1" "vue-cli-plugin-i18n": "~2.3.1"
}, },
"eslintConfig": { "eslintConfig": {

View File

@ -29,10 +29,10 @@
import StatCard from '@/components/Common/StatCard.vue' import StatCard from '@/components/Common/StatCard.vue'
import { TUnit } from '@/types/units' import { TUnit } from '@/types/units'
import { IUserProfile } from '@/types/user' import { IAuthUserProfile } from '@/types/user'
import { convertDistance, units } from '@/utils/units' import { convertDistance, units } from '@/utils/units'
interface Props { interface Props {
user: IUserProfile user: IAuthUserProfile
} }
const props = defineProps<Props>() const props = defineProps<Props>()
@ -47,9 +47,11 @@
const unitTo: TUnit = user.value.imperial_units const unitTo: TUnit = user.value.imperial_units
? units[defaultUnitFrom].defaultTarget ? units[defaultUnitFrom].defaultTarget
: defaultUnitFrom : defaultUnitFrom
const totalDistance = user.value.imperial_units const totalDistance: ComputedRef<number> = computed(() =>
? convertDistance(user.value.total_distance, defaultUnitFrom, unitTo, 2) user.value.imperial_units
: parseFloat(user.value.total_distance.toFixed(2)) ? convertDistance(user.value.total_distance, defaultUnitFrom, unitTo, 2)
: parseFloat(user.value.total_distance.toFixed(2))
)
function get_duration(total_duration: ComputedRef<string>) { function get_duration(total_duration: ComputedRef<string>) {
const duration = total_duration.value.match(/day/g) const duration = total_duration.value.match(/day/g)

View File

@ -263,7 +263,7 @@ const routes: Array<RouteRecordRaw> = [
}, },
{ {
path: 'users/:username', path: 'users/:username',
name: 'User', name: 'UserFromAdmin',
component: () => component: () =>
import(/* webpackChunkName: 'profile' */ '@/views/user/UserView.vue'), import(/* webpackChunkName: 'profile' */ '@/views/user/UserView.vue'),
props: { fromAdmin: true }, props: { fromAdmin: true },

View File

@ -1456,7 +1456,7 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@typescript-eslint/eslint-plugin@^5.0.0", "@typescript-eslint/eslint-plugin@^5.4.0": "@typescript-eslint/eslint-plugin@^5.0.0":
version "5.16.0" version "5.16.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.16.0.tgz#78f246dd8d1b528fc5bfca99a8a64d4023a3d86d" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.16.0.tgz#78f246dd8d1b528fc5bfca99a8a64d4023a3d86d"
integrity sha512-SJoba1edXvQRMmNI505Uo4XmGbxCK9ARQpkvOd00anxzri9RNQk0DDCxD+LIl+jYhkzOJiOMMKYEHnHEODjdCw== integrity sha512-SJoba1edXvQRMmNI505Uo4XmGbxCK9ARQpkvOd00anxzri9RNQk0DDCxD+LIl+jYhkzOJiOMMKYEHnHEODjdCw==
@ -1471,7 +1471,22 @@
semver "^7.3.5" semver "^7.3.5"
tsutils "^3.21.0" tsutils "^3.21.0"
"@typescript-eslint/parser@^5.0.0", "@typescript-eslint/parser@^5.4.0": "@typescript-eslint/eslint-plugin@^5.17.0":
version "5.17.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.17.0.tgz#704eb4e75039000531255672bf1c85ee85cf1d67"
integrity sha512-qVstvQilEd89HJk3qcbKt/zZrfBZ+9h2ynpAGlWjWiizA7m/MtLT9RoX6gjtpE500vfIg8jogAkDzdCxbsFASQ==
dependencies:
"@typescript-eslint/scope-manager" "5.17.0"
"@typescript-eslint/type-utils" "5.17.0"
"@typescript-eslint/utils" "5.17.0"
debug "^4.3.2"
functional-red-black-tree "^1.0.1"
ignore "^5.1.8"
regexpp "^3.2.0"
semver "^7.3.5"
tsutils "^3.21.0"
"@typescript-eslint/parser@^5.0.0":
version "5.16.0" version "5.16.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.16.0.tgz#e4de1bde4b4dad5b6124d3da227347616ed55508" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.16.0.tgz#e4de1bde4b4dad5b6124d3da227347616ed55508"
integrity sha512-fkDq86F0zl8FicnJtdXakFs4lnuebH6ZADDw6CYQv0UZeIjHvmEw87m9/29nk2Dv5Lmdp0zQ3zDQhiMWQf/GbA== integrity sha512-fkDq86F0zl8FicnJtdXakFs4lnuebH6ZADDw6CYQv0UZeIjHvmEw87m9/29nk2Dv5Lmdp0zQ3zDQhiMWQf/GbA==
@ -1481,6 +1496,16 @@
"@typescript-eslint/typescript-estree" "5.16.0" "@typescript-eslint/typescript-estree" "5.16.0"
debug "^4.3.2" debug "^4.3.2"
"@typescript-eslint/parser@^5.17.0":
version "5.17.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.17.0.tgz#7def77d5bcd8458d12d52909118cf3f0a45f89d5"
integrity sha512-aRzW9Jg5Rlj2t2/crzhA2f23SIYFlF9mchGudyP0uiD6SenIxzKoLjwzHbafgHn39dNV/TV7xwQkLfFTZlJ4ig==
dependencies:
"@typescript-eslint/scope-manager" "5.17.0"
"@typescript-eslint/types" "5.17.0"
"@typescript-eslint/typescript-estree" "5.17.0"
debug "^4.3.2"
"@typescript-eslint/scope-manager@5.16.0": "@typescript-eslint/scope-manager@5.16.0":
version "5.16.0" version "5.16.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.16.0.tgz#7e7909d64bd0c4d8aef629cdc764b9d3e1d3a69a" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.16.0.tgz#7e7909d64bd0c4d8aef629cdc764b9d3e1d3a69a"
@ -1489,6 +1514,14 @@
"@typescript-eslint/types" "5.16.0" "@typescript-eslint/types" "5.16.0"
"@typescript-eslint/visitor-keys" "5.16.0" "@typescript-eslint/visitor-keys" "5.16.0"
"@typescript-eslint/scope-manager@5.17.0":
version "5.17.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.17.0.tgz#4cea7d0e0bc0e79eb60cad431c89120987c3f952"
integrity sha512-062iCYQF/doQ9T2WWfJohQKKN1zmmXVfAcS3xaiialiw8ZUGy05Em6QVNYJGO34/sU1a7a+90U3dUNfqUDHr3w==
dependencies:
"@typescript-eslint/types" "5.17.0"
"@typescript-eslint/visitor-keys" "5.17.0"
"@typescript-eslint/type-utils@5.16.0": "@typescript-eslint/type-utils@5.16.0":
version "5.16.0" version "5.16.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.16.0.tgz#b482bdde1d7d7c0c7080f7f2f67ea9580b9e0692" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.16.0.tgz#b482bdde1d7d7c0c7080f7f2f67ea9580b9e0692"
@ -1498,11 +1531,25 @@
debug "^4.3.2" debug "^4.3.2"
tsutils "^3.21.0" tsutils "^3.21.0"
"@typescript-eslint/type-utils@5.17.0":
version "5.17.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.17.0.tgz#1c4549d68c89877662224aabb29fbbebf5fc9672"
integrity sha512-3hU0RynUIlEuqMJA7dragb0/75gZmwNwFf/QJokWzPehTZousP/MNifVSgjxNcDCkM5HI2K22TjQWUmmHUINSg==
dependencies:
"@typescript-eslint/utils" "5.17.0"
debug "^4.3.2"
tsutils "^3.21.0"
"@typescript-eslint/types@5.16.0": "@typescript-eslint/types@5.16.0":
version "5.16.0" version "5.16.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.16.0.tgz#5827b011982950ed350f075eaecb7f47d3c643ee" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.16.0.tgz#5827b011982950ed350f075eaecb7f47d3c643ee"
integrity sha512-oUorOwLj/3/3p/HFwrp6m/J2VfbLC8gjW5X3awpQJ/bSG+YRGFS4dpsvtQ8T2VNveV+LflQHjlLvB6v0R87z4g== integrity sha512-oUorOwLj/3/3p/HFwrp6m/J2VfbLC8gjW5X3awpQJ/bSG+YRGFS4dpsvtQ8T2VNveV+LflQHjlLvB6v0R87z4g==
"@typescript-eslint/types@5.17.0":
version "5.17.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.17.0.tgz#861ec9e669ffa2aa9b873dd4d28d9b1ce26d216f"
integrity sha512-AgQ4rWzmCxOZLioFEjlzOI3Ch8giDWx8aUDxyNw9iOeCvD3GEYAB7dxWGQy4T/rPVe8iPmu73jPHuaSqcjKvxw==
"@typescript-eslint/typescript-estree@5.16.0": "@typescript-eslint/typescript-estree@5.16.0":
version "5.16.0" version "5.16.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.16.0.tgz#32259459ec62f5feddca66adc695342f30101f61" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.16.0.tgz#32259459ec62f5feddca66adc695342f30101f61"
@ -1516,6 +1563,19 @@
semver "^7.3.5" semver "^7.3.5"
tsutils "^3.21.0" tsutils "^3.21.0"
"@typescript-eslint/typescript-estree@5.17.0":
version "5.17.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.17.0.tgz#a7cba7dfc8f9cc2ac78c18584e684507df4f2488"
integrity sha512-X1gtjEcmM7Je+qJRhq7ZAAaNXYhTgqMkR10euC4Si6PIjb+kwEQHSxGazXUQXFyqfEXdkGf6JijUu5R0uceQzg==
dependencies:
"@typescript-eslint/types" "5.17.0"
"@typescript-eslint/visitor-keys" "5.17.0"
debug "^4.3.2"
globby "^11.0.4"
is-glob "^4.0.3"
semver "^7.3.5"
tsutils "^3.21.0"
"@typescript-eslint/utils@5.16.0": "@typescript-eslint/utils@5.16.0":
version "5.16.0" version "5.16.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.16.0.tgz#42218b459d6d66418a4eb199a382bdc261650679" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.16.0.tgz#42218b459d6d66418a4eb199a382bdc261650679"
@ -1528,6 +1588,18 @@
eslint-scope "^5.1.1" eslint-scope "^5.1.1"
eslint-utils "^3.0.0" eslint-utils "^3.0.0"
"@typescript-eslint/utils@5.17.0":
version "5.17.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.17.0.tgz#549a9e1d491c6ccd3624bc3c1b098f5cfb45f306"
integrity sha512-DVvndq1QoxQH+hFv+MUQHrrWZ7gQ5KcJzyjhzcqB1Y2Xes1UQQkTRPUfRpqhS8mhTWsSb2+iyvDW1Lef5DD7vA==
dependencies:
"@types/json-schema" "^7.0.9"
"@typescript-eslint/scope-manager" "5.17.0"
"@typescript-eslint/types" "5.17.0"
"@typescript-eslint/typescript-estree" "5.17.0"
eslint-scope "^5.1.1"
eslint-utils "^3.0.0"
"@typescript-eslint/visitor-keys@5.16.0": "@typescript-eslint/visitor-keys@5.16.0":
version "5.16.0" version "5.16.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.16.0.tgz#f27dc3b943e6317264c7492e390c6844cd4efbbb" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.16.0.tgz#f27dc3b943e6317264c7492e390c6844cd4efbbb"
@ -1536,6 +1608,14 @@
"@typescript-eslint/types" "5.16.0" "@typescript-eslint/types" "5.16.0"
eslint-visitor-keys "^3.0.0" eslint-visitor-keys "^3.0.0"
"@typescript-eslint/visitor-keys@5.17.0":
version "5.17.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.17.0.tgz#52daae45c61b0211b4c81b53a71841911e479128"
integrity sha512-6K/zlc4OfCagUu7Am/BD5k8PSWQOgh34Nrv9Rxe2tBzlJ7uOeJ/h7ugCGDCeEZHT6k2CJBhbk9IsbkPI0uvUkA==
dependencies:
"@typescript-eslint/types" "5.17.0"
eslint-visitor-keys "^3.0.0"
"@ungap/promise-all-settled@1.1.2": "@ungap/promise-all-settled@1.1.2":
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44"
@ -3198,10 +3278,10 @@ data-urls@^3.0.1:
whatwg-mimetype "^3.0.0" whatwg-mimetype "^3.0.0"
whatwg-url "^10.0.0" whatwg-url "^10.0.0"
date-fns-tz@^1.3.1: date-fns-tz@^1.3.3:
version "1.3.1" version "1.3.3"
resolved "https://registry.yarnpkg.com/date-fns-tz/-/date-fns-tz-1.3.1.tgz#88b6374e5a74cfb11ec2d2b120cfe0bc02eeb862" resolved "https://registry.yarnpkg.com/date-fns-tz/-/date-fns-tz-1.3.3.tgz#7884a4b3ed6cd95bfd81831d608e5ef8be500c86"
integrity sha512-Uy+wph6HcQ0IG8TWbVyXicgDmB1zdvb0CoIknZQaxiTun4uSfxLR+8gSTC2C3KCLq+0fEIuEtJ/ORDRIn6doQw== integrity sha512-Gks46gwbSauBQnV3Oofluj1wTm8J0tM7sbSJ9P+cJq/ZnTCpMohTKmmO5Tn+jQ7dyn0+b8G7cY4O2DZ5P/LXcA==
date-fns@^2.28.0: date-fns@^2.28.0:
version "2.28.0" version "2.28.0"
@ -3646,10 +3726,10 @@ eslint-import-resolver-node@^0.3.6:
debug "^3.2.7" debug "^3.2.7"
resolve "^1.20.0" resolve "^1.20.0"
eslint-import-resolver-typescript@^2.7.0: eslint-import-resolver-typescript@^2.7.1:
version "2.7.0" version "2.7.1"
resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.7.0.tgz#1f9d391b636dccdbaa4a3b1a87eb9a8237e23963" resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.7.1.tgz#a90a4a1c80da8d632df25994c4c5fdcdd02b8751"
integrity sha512-MNHS3u5pebvROX4MjGP9coda589ZGfL1SqdxUV4kSrcclfDRWvNE2D+eljbnWVMvWDVRgT89nhscMHPKYGcObQ== integrity sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==
dependencies: dependencies:
debug "^4.3.4" debug "^4.3.4"
glob "^7.2.0" glob "^7.2.0"
@ -6317,11 +6397,16 @@ prettier-linter-helpers@^1.0.0:
dependencies: dependencies:
fast-diff "^1.1.2" fast-diff "^1.1.2"
"prettier@^1.18.2 || ^2.0.0", prettier@^2.6.1: "prettier@^1.18.2 || ^2.0.0":
version "2.6.1" version "2.6.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.1.tgz#d472797e0d7461605c1609808e27b80c0f9cfe17" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.1.tgz#d472797e0d7461605c1609808e27b80c0f9cfe17"
integrity sha512-8UVbTBYGwN37Bs9LERmxCPjdvPxlEowx2urIL6urHzdb3SDq4B/Z6xLFCblrSnE4iKWcS6ziJ3aOYrc1kz/E2A== integrity sha512-8UVbTBYGwN37Bs9LERmxCPjdvPxlEowx2urIL6urHzdb3SDq4B/Z6xLFCblrSnE4iKWcS6ziJ3aOYrc1kz/E2A==
prettier@^2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032"
integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==
pretty-bytes@^5.3.0, pretty-bytes@^5.4.1: pretty-bytes@^5.3.0, pretty-bytes@^5.4.1:
version "5.6.0" version "5.6.0"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
@ -6673,10 +6758,10 @@ sass-loader@^12.6.0:
klona "^2.0.4" klona "^2.0.4"
neo-async "^2.6.2" neo-async "^2.6.2"
sass@^1.49.9: sass@^1.49.11:
version "1.49.9" version "1.49.11"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.49.9.tgz#b15a189ecb0ca9e24634bae5d1ebc191809712f9" resolved "https://registry.yarnpkg.com/sass/-/sass-1.49.11.tgz#1ffeb77faeed8b806a2a1e021d7c9fd3fc322cb7"
integrity sha512-YlYWkkHP9fbwaFRZQRXgDi3mXZShslVmmo+FVK3kHLUELHHEYrCmL1x6IUjC7wLS6VuJSAFXRQS/DxdsC4xL1A== integrity sha512-wvS/geXgHUGs6A/4ud5BFIWKO1nKd7wYIGimDk4q4GFkJicILActpv9ueMT4eRGSsp1BdKHuw1WwAHXbhsJELQ==
dependencies: dependencies:
chokidar ">=3.0.0 <4.0.0" chokidar ">=3.0.0 <4.0.0"
immutable "^4.0.0" immutable "^4.0.0"
@ -7471,10 +7556,10 @@ type-is@~1.6.18:
media-typer "0.3.0" media-typer "0.3.0"
mime-types "~2.1.24" mime-types "~2.1.24"
typescript@~4.5.5: typescript@^4.6.3:
version "4.5.5" version "4.6.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.3.tgz#eefeafa6afdd31d725584c67a0eaba80f6fc6c6c"
integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA== integrity sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==
unbox-primitive@^1.0.1: unbox-primitive@^1.0.1:
version "1.0.1" version "1.0.1"

223
poetry.lock generated
View File

@ -93,7 +93,7 @@ typecheck = ["mypy"]
[[package]] [[package]]
name = "black" name = "black"
version = "22.1.0" version = "22.3.0"
description = "The uncompromising code formatter." description = "The uncompromising code formatter."
category = "dev" category = "dev"
optional = false optional = false
@ -104,7 +104,7 @@ click = ">=8.0.0"
mypy-extensions = ">=0.4.3" mypy-extensions = ">=0.4.3"
pathspec = ">=0.9.0" pathspec = ">=0.9.0"
platformdirs = ">=2" platformdirs = ">=2"
tomli = ">=1.1.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""}
typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}
@ -146,11 +146,11 @@ unicode_backport = ["unicodedata2"]
[[package]] [[package]]
name = "click" name = "click"
version = "8.0.4" version = "8.1.2"
description = "Composable command line interface toolkit" description = "Composable command line interface toolkit"
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.7"
[package.dependencies] [package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""} colorama = {version = "*", markers = "platform_system == \"Windows\""}
@ -232,7 +232,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]] [[package]]
name = "dramatiq" name = "dramatiq"
version = "1.12.3" version = "1.13.0"
description = "Background Processing for Python 3." description = "Background Processing for Python 3."
category = "main" category = "main"
optional = false optional = false
@ -243,8 +243,8 @@ prometheus-client = ">=0.2"
redis = {version = ">=2.0,<5.0", optional = true, markers = "extra == \"redis\""} redis = {version = ">=2.0,<5.0", optional = true, markers = "extra == \"redis\""}
[package.extras] [package.extras]
all = ["gevent (>=1.1)", "redis (>=2.0,<5.0)", "watchdog", "pika (>=1.0,<2.0)", "watchdog-gevent", "pylibmc (>=1.5,<2.0)"] all = ["redis (>=2.0,<5.0)", "pylibmc (>=1.5,<2.0)", "watchdog", "watchdog-gevent", "pika (>=1.0,<2.0)", "gevent (>=1.1)"]
dev = ["gevent (>=1.1)", "redis (>=2.0,<5.0)", "watchdog", "pika (>=1.0,<2.0)", "watchdog-gevent", "pylibmc (>=1.5,<2.0)", "alabaster", "sphinx (<1.8)", "sphinxcontrib-napoleon", "flake8", "flake8-bugbear", "flake8-quotes", "isort", "bumpversion", "hiredis", "twine", "wheel", "pytest", "pytest-benchmark", "pytest-cov", "tox"] dev = ["redis (>=2.0,<5.0)", "pylibmc (>=1.5,<2.0)", "watchdog", "watchdog-gevent", "pika (>=1.0,<2.0)", "gevent (>=1.1)", "alabaster", "sphinx (<1.8)", "sphinxcontrib-napoleon", "flake8", "flake8-bugbear", "flake8-quotes", "isort", "bumpversion", "hiredis", "twine", "wheel", "pytest", "pytest-benchmark", "pytest-cov", "tox"]
gevent = ["gevent (>=1.1)"] gevent = ["gevent (>=1.1)"]
memcached = ["pylibmc (>=1.5,<2.0)"] memcached = ["pylibmc (>=1.5,<2.0)"]
rabbitmq = ["pika (>=1.0,<2.0)"] rabbitmq = ["pika (>=1.0,<2.0)"]
@ -267,14 +267,15 @@ pyflakes = ">=2.3.0,<2.4.0"
[[package]] [[package]]
name = "flask" name = "flask"
version = "2.0.3" version = "2.1.1"
description = "A simple framework for building complex web applications." description = "A simple framework for building complex web applications."
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.7"
[package.dependencies] [package.dependencies]
click = ">=7.1.2" click = ">=8.0"
importlib-metadata = {version = ">=3.6.0", markers = "python_version < \"3.10\""}
itsdangerous = ">=2.0" itsdangerous = ">=2.0"
Jinja2 = ">=3.0" Jinja2 = ">=3.0"
Werkzeug = ">=2.0" Werkzeug = ">=2.0"
@ -285,14 +286,14 @@ dotenv = ["python-dotenv"]
[[package]] [[package]]
name = "flask-bcrypt" name = "flask-bcrypt"
version = "0.7.1" version = "1.0.0"
description = "Brcrypt hashing for Flask." description = "Brcrypt hashing for Flask."
category = "main" category = "main"
optional = false optional = false
python-versions = "*" python-versions = "*"
[package.dependencies] [package.dependencies]
bcrypt = "*" bcrypt = ">=3.1.1"
Flask = "*" Flask = "*"
[[package]] [[package]]
@ -584,12 +585,16 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
[[package]] [[package]]
name = "pillow" name = "pillow"
version = "9.0.1" version = "9.1.0"
description = "Python Imaging Library (Fork)" description = "Python Imaging Library (Fork)"
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
[package.extras]
docs = ["olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinx-rtd-theme (>=1.0)", "sphinxext-opengraph"]
tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
[[package]] [[package]]
name = "platformdirs" name = "platformdirs"
version = "2.5.1" version = "2.5.1"
@ -748,14 +753,14 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.
[[package]] [[package]]
name = "pytest-base-url" name = "pytest-base-url"
version = "1.4.2" version = "2.0.0"
description = "pytest plugin for URL based testing" description = "pytest plugin for URL based testing"
category = "dev" category = "dev"
optional = false optional = false
python-versions = "*" python-versions = ">=3.7,<4.0"
[package.dependencies] [package.dependencies]
pytest = ">=2.7.3" pytest = ">=3.0.0,<8.0.0"
requests = ">=2.9" requests = ">=2.9"
[[package]] [[package]]
@ -928,7 +933,7 @@ sphinx = ">=1.3.1"
[[package]] [[package]]
name = "redis" name = "redis"
version = "4.2.0" version = "4.2.1"
description = "Python client for Redis database and key-value store" description = "Python client for Redis database and key-value store"
category = "main" category = "main"
optional = false optional = false
@ -939,7 +944,7 @@ async-timeout = ">=4.0.2"
deprecated = ">=1.2.3" deprecated = ">=1.2.3"
importlib-metadata = {version = ">=1.0", markers = "python_version < \"3.8\""} importlib-metadata = {version = ">=1.0", markers = "python_version < \"3.8\""}
packaging = ">=20.4" packaging = ">=20.4"
typing-extensions = "*" typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
[package.extras] [package.extras]
hiredis = ["hiredis (>=1.0.0)"] hiredis = ["hiredis (>=1.0.0)"]
@ -1033,7 +1038,7 @@ python-versions = "*"
[[package]] [[package]]
name = "sphinx" name = "sphinx"
version = "4.4.0" version = "4.5.0"
description = "Python documentation generator" description = "Python documentation generator"
category = "dev" category = "dev"
optional = false optional = false
@ -1269,7 +1274,7 @@ python-versions = ">=3.6"
[[package]] [[package]]
name = "types-freezegun" name = "types-freezegun"
version = "1.1.7" version = "1.1.8"
description = "Typing stubs for freezegun" description = "Typing stubs for freezegun"
category = "dev" category = "dev"
optional = false optional = false
@ -1285,7 +1290,7 @@ python-versions = "*"
[[package]] [[package]]
name = "types-requests" name = "types-requests"
version = "2.27.15" version = "2.27.16"
description = "Typing stubs for requests" description = "Typing stubs for requests"
category = "dev" category = "dev"
optional = false optional = false
@ -1310,6 +1315,14 @@ category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
[[package]]
name = "ua-parser"
version = "0.10.0"
description = "Python port of Browserscope's user agent parser"
category = "main"
optional = false
python-versions = "*"
[[package]] [[package]]
name = "urllib3" name = "urllib3"
version = "1.26.9" version = "1.26.9"
@ -1332,11 +1345,11 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
[[package]] [[package]]
name = "werkzeug" name = "werkzeug"
version = "2.0.3" version = "2.1.1"
description = "The comprehensive WSGI web application library." description = "The comprehensive WSGI web application library."
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.7"
[package.extras] [package.extras]
watchdog = ["watchdog"] watchdog = ["watchdog"]
@ -1375,7 +1388,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.7" python-versions = "^3.7"
content-hash = "545f5ef79ba67d5a2d2df007fb5ac67ca37630efd4ff04c3a15e181c73b4f466" content-hash = "e130b306957d6577ecd21cc1a19daa81073d5bbe77ba9f6a60ff83d8af0a2f05"
[metadata.files] [metadata.files]
alabaster = [ alabaster = [
@ -1416,29 +1429,29 @@ bcrypt = [
{file = "bcrypt-3.2.0.tar.gz", hash = "sha256:5b93c1726e50a93a033c36e5ca7fdcd29a5c7395af50a6892f5d9e7c6cfbfb29"}, {file = "bcrypt-3.2.0.tar.gz", hash = "sha256:5b93c1726e50a93a033c36e5ca7fdcd29a5c7395af50a6892f5d9e7c6cfbfb29"},
] ]
black = [ black = [
{file = "black-22.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1297c63b9e1b96a3d0da2d85d11cd9bf8664251fd69ddac068b98dc4f34f73b6"}, {file = "black-22.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09"},
{file = "black-22.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2ff96450d3ad9ea499fc4c60e425a1439c2120cbbc1ab959ff20f7c76ec7e866"}, {file = "black-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb"},
{file = "black-22.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e21e1f1efa65a50e3960edd068b6ae6d64ad6235bd8bfea116a03b21836af71"}, {file = "black-22.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e3556168e2e5c49629f7b0f377070240bd5511e45e25a4497bb0073d9dda776a"},
{file = "black-22.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2f69158a7d120fd641d1fa9a921d898e20d52e44a74a6fbbcc570a62a6bc8ab"}, {file = "black-22.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67c8301ec94e3bcc8906740fe071391bce40a862b7be0b86fb5382beefecd968"},
{file = "black-22.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:228b5ae2c8e3d6227e4bde5920d2fc66cc3400fde7bcc74f480cb07ef0b570d5"}, {file = "black-22.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d"},
{file = "black-22.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b1a5ed73ab4c482208d20434f700d514f66ffe2840f63a6252ecc43a9bc77e8a"}, {file = "black-22.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cc1e1de68c8e5444e8f94c3670bb48a2beef0e91dddfd4fcc29595ebd90bb9ce"},
{file = "black-22.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35944b7100af4a985abfcaa860b06af15590deb1f392f06c8683b4381e8eeaf0"}, {file = "black-22.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2fc92002d44746d3e7db7cf9313cf4452f43e9ea77a2c939defce3b10b5c82"},
{file = "black-22.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7835fee5238fc0a0baf6c9268fb816b5f5cd9b8793423a75e8cd663c48d073ba"}, {file = "black-22.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a6342964b43a99dbc72f72812bf88cad8f0217ae9acb47c0d4f141a6416d2d7b"},
{file = "black-22.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dae63f2dbf82882fa3b2a3c49c32bffe144970a573cd68d247af6560fc493ae1"}, {file = "black-22.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:328efc0cc70ccb23429d6be184a15ce613f676bdfc85e5fe8ea2a9354b4e9015"},
{file = "black-22.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fa1db02410b1924b6749c245ab38d30621564e658297484952f3d8a39fce7e8"}, {file = "black-22.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06f9d8846f2340dfac80ceb20200ea5d1b3f181dd0556b47af4e8e0b24fa0a6b"},
{file = "black-22.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c8226f50b8c34a14608b848dc23a46e5d08397d009446353dad45e04af0c8e28"}, {file = "black-22.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4efa5fad66b903b4a5f96d91461d90b9507a812b3c5de657d544215bb7877a"},
{file = "black-22.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2d6f331c02f0f40aa51a22e479c8209d37fcd520c77721c034517d44eecf5912"}, {file = "black-22.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8477ec6bbfe0312c128e74644ac8a02ca06bcdb8982d4ee06f209be28cdf163"},
{file = "black-22.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:742ce9af3086e5bd07e58c8feb09dbb2b047b7f566eb5f5bc63fd455814979f3"}, {file = "black-22.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:637a4014c63fbf42a692d22b55d8ad6968a946b4a6ebc385c5505d9625b6a464"},
{file = "black-22.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fdb8754b453fb15fad3f72cd9cad3e16776f0964d67cf30ebcbf10327a3777a3"}, {file = "black-22.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:863714200ada56cbc366dc9ae5291ceb936573155f8bf8e9de92aef51f3ad0f0"},
{file = "black-22.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5660feab44c2e3cb24b2419b998846cbb01c23c7fe645fee45087efa3da2d61"}, {file = "black-22.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10dbe6e6d2988049b4655b2b739f98785a884d4d6b85bc35133a8fb9a2233176"},
{file = "black-22.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:6f2f01381f91c1efb1451998bd65a129b3ed6f64f79663a55fe0e9b74a5f81fd"}, {file = "black-22.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:cee3e11161dde1b2a33a904b850b0899e0424cc331b7295f2a9698e79f9a69a0"},
{file = "black-22.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:efbadd9b52c060a8fc3b9658744091cb33c31f830b3f074422ed27bad2b18e8f"}, {file = "black-22.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5891ef8abc06576985de8fa88e95ab70641de6c1fca97e2a15820a9b69e51b20"},
{file = "black-22.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8871fcb4b447206904932b54b567923e5be802b9b19b744fdff092bd2f3118d0"}, {file = "black-22.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:30d78ba6bf080eeaf0b7b875d924b15cd46fec5fd044ddfbad38c8ea9171043a"},
{file = "black-22.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccad888050f5393f0d6029deea2a33e5ae371fd182a697313bdbd835d3edaf9c"}, {file = "black-22.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ee8f1f7228cce7dffc2b464f07ce769f478968bfb3dd1254a4c2eeed84928aad"},
{file = "black-22.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07e5c049442d7ca1a2fc273c79d1aecbbf1bc858f62e8184abe1ad175c4f7cc2"}, {file = "black-22.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ee227b696ca60dd1c507be80a6bc849a5a6ab57ac7352aad1ffec9e8b805f21"},
{file = "black-22.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:373922fc66676133ddc3e754e4509196a8c392fec3f5ca4486673e685a421321"}, {file = "black-22.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:9b542ced1ec0ceeff5b37d69838106a6348e60db7b8fdd245294dc1d26136265"},
{file = "black-22.1.0-py3-none-any.whl", hash = "sha256:3524739d76b6b3ed1132422bf9d82123cd1705086723bc3e235ca39fd21c667d"}, {file = "black-22.3.0-py3-none-any.whl", hash = "sha256:bc58025940a896d7e5356952228b68f793cf5fcb342be703c3a2669a1488cb72"},
{file = "black-22.1.0.tar.gz", hash = "sha256:a7c0192d35635f6fc1174be575cb7915e92e5dd629ee79fdaf0dcfa41a80afb5"}, {file = "black-22.3.0.tar.gz", hash = "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79"},
] ]
certifi = [ certifi = [
{file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"},
@ -1501,8 +1514,8 @@ charset-normalizer = [
{file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"},
] ]
click = [ click = [
{file = "click-8.0.4-py3-none-any.whl", hash = "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1"}, {file = "click-8.1.2-py3-none-any.whl", hash = "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e"},
{file = "click-8.0.4.tar.gz", hash = "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"}, {file = "click-8.1.2.tar.gz", hash = "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72"},
] ]
colorama = [ colorama = [
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
@ -1586,19 +1599,20 @@ docutils = [
{file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"},
] ]
dramatiq = [ dramatiq = [
{file = "dramatiq-1.12.3-py3-none-any.whl", hash = "sha256:eccb0f54d44ebd9e2c79e00d67b808397589a1a621ba7c5fd58df5fb6204a0a8"}, {file = "dramatiq-1.13.0-py3-none-any.whl", hash = "sha256:8ef7509ca62bc45c3f1e3b1a0248e9f774337100e32ba1502cfcca15df79ad61"},
{file = "dramatiq-1.12.3.tar.gz", hash = "sha256:380bd77b6b19d642f417b642935049ff71ddf4b4e57d821e4f55b92541430f21"}, {file = "dramatiq-1.13.0.tar.gz", hash = "sha256:b4fe0ca6b55b06bebf82cd14c88044fb267505a57d4aa47378194efa0cef5f47"},
] ]
flake8 = [ flake8 = [
{file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"},
{file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"},
] ]
flask = [ flask = [
{file = "Flask-2.0.3-py3-none-any.whl", hash = "sha256:59da8a3170004800a2837844bfa84d49b022550616070f7cb1a659682b2e7c9f"}, {file = "Flask-2.1.1-py3-none-any.whl", hash = "sha256:8a4cf32d904cf5621db9f0c9fbcd7efabf3003f22a04e4d0ce790c7137ec5264"},
{file = "Flask-2.0.3.tar.gz", hash = "sha256:e1120c228ca2f553b470df4a5fa927ab66258467526069981b3eb0a91902687d"}, {file = "Flask-2.1.1.tar.gz", hash = "sha256:a8c9bd3e558ec99646d177a9739c41df1ded0629480b4c8d2975412f3c9519c8"},
] ]
flask-bcrypt = [ flask-bcrypt = [
{file = "Flask-Bcrypt-0.7.1.tar.gz", hash = "sha256:d71c8585b2ee1c62024392ebdbc447438564e2c8c02b4e57b56a4cafd8d13c5f"}, {file = "Flask-Bcrypt-1.0.0.tar.gz", hash = "sha256:e622fbd3b0bf63d516b8844fe3431fc30213592412b430036c3928a0c52dfb27"},
{file = "Flask_Bcrypt-1.0.0-py3-none-any.whl", hash = "sha256:64a947e15ff06823c3843f4826d4548dfae038c7df8f98ea82755db62092ec4c"},
] ]
flask-dramatiq = [ flask-dramatiq = [
{file = "flask-dramatiq-0.6.0.tar.gz", hash = "sha256:63709e73d7c8d2e5d9bc554d1e859d91c5c5c9a4ebc9461752655bf1e0b87420"}, {file = "flask-dramatiq-0.6.0.tar.gz", hash = "sha256:63709e73d7c8d2e5d9bc554d1e859d91c5c5c9a4ebc9461752655bf1e0b87420"},
@ -1806,41 +1820,44 @@ pathspec = [
{file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
] ]
pillow = [ pillow = [
{file = "Pillow-9.0.1-1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a5d24e1d674dd9d72c66ad3ea9131322819ff86250b30dc5821cbafcfa0b96b4"}, {file = "Pillow-9.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:af79d3fde1fc2e33561166d62e3b63f0cc3e47b5a3a2e5fea40d4917754734ea"},
{file = "Pillow-9.0.1-1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2632d0f846b7c7600edf53c48f8f9f1e13e62f66a6dbc15191029d950bfed976"}, {file = "Pillow-9.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:55dd1cf09a1fd7c7b78425967aacae9b0d70125f7d3ab973fadc7b5abc3de652"},
{file = "Pillow-9.0.1-1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b9618823bd237c0d2575283f2939655f54d51b4527ec3972907a927acbcc5bfc"}, {file = "Pillow-9.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:66822d01e82506a19407d1afc104c3fcea3b81d5eb11485e593ad6b8492f995a"},
{file = "Pillow-9.0.1-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:9bfdb82cdfeccec50aad441afc332faf8606dfa5e8efd18a6692b5d6e79f00fd"}, {file = "Pillow-9.1.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a5eaf3b42df2bcda61c53a742ee2c6e63f777d0e085bbc6b2ab7ed57deb13db7"},
{file = "Pillow-9.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5100b45a4638e3c00e4d2320d3193bdabb2d75e79793af7c3eb139e4f569f16f"}, {file = "Pillow-9.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01ce45deec9df310cbbee11104bae1a2a43308dd9c317f99235b6d3080ddd66e"},
{file = "Pillow-9.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:528a2a692c65dd5cafc130de286030af251d2ee0483a5bf50c9348aefe834e8a"}, {file = "Pillow-9.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:aea7ce61328e15943d7b9eaca87e81f7c62ff90f669116f857262e9da4057ba3"},
{file = "Pillow-9.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f29d831e2151e0b7b39981756d201f7108d3d215896212ffe2e992d06bfe049"}, {file = "Pillow-9.1.0-cp310-cp310-win32.whl", hash = "sha256:7a053bd4d65a3294b153bdd7724dce864a1d548416a5ef61f6d03bf149205160"},
{file = "Pillow-9.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:855c583f268edde09474b081e3ddcd5cf3b20c12f26e0d434e1386cc5d318e7a"}, {file = "Pillow-9.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:97bda660702a856c2c9e12ec26fc6d187631ddfd896ff685814ab21ef0597033"},
{file = "Pillow-9.0.1-cp310-cp310-win32.whl", hash = "sha256:d9d7942b624b04b895cb95af03a23407f17646815495ce4547f0e60e0b06f58e"}, {file = "Pillow-9.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:21dee8466b42912335151d24c1665fcf44dc2ee47e021d233a40c3ca5adae59c"},
{file = "Pillow-9.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:81c4b81611e3a3cb30e59b0cf05b888c675f97e3adb2c8672c3154047980726b"}, {file = "Pillow-9.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b6d4050b208c8ff886fd3db6690bf04f9a48749d78b41b7a5bf24c236ab0165"},
{file = "Pillow-9.0.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:413ce0bbf9fc6278b2d63309dfeefe452835e1c78398efb431bab0672fe9274e"}, {file = "Pillow-9.1.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5cfca31ab4c13552a0f354c87fbd7f162a4fafd25e6b521bba93a57fe6a3700a"},
{file = "Pillow-9.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80fe64a6deb6fcfdf7b8386f2cf216d329be6f2781f7d90304351811fb591360"}, {file = "Pillow-9.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed742214068efa95e9844c2d9129e209ed63f61baa4d54dbf4cf8b5e2d30ccf2"},
{file = "Pillow-9.0.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cef9c85ccbe9bee00909758936ea841ef12035296c748aaceee535969e27d31b"}, {file = "Pillow-9.1.0-cp37-cp37m-win32.whl", hash = "sha256:c9efef876c21788366ea1f50ecb39d5d6f65febe25ad1d4c0b8dff98843ac244"},
{file = "Pillow-9.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d19397351f73a88904ad1aee421e800fe4bbcd1aeee6435fb62d0a05ccd1030"}, {file = "Pillow-9.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:de344bcf6e2463bb25179d74d6e7989e375f906bcec8cb86edb8b12acbc7dfef"},
{file = "Pillow-9.0.1-cp37-cp37m-win32.whl", hash = "sha256:d21237d0cd37acded35154e29aec853e945950321dd2ffd1a7d86fe686814669"}, {file = "Pillow-9.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:17869489de2fce6c36690a0c721bd3db176194af5f39249c1ac56d0bb0fcc512"},
{file = "Pillow-9.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ede5af4a2702444a832a800b8eb7f0a7a1c0eed55b644642e049c98d589e5092"}, {file = "Pillow-9.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:25023a6209a4d7c42154073144608c9a71d3512b648a2f5d4465182cb93d3477"},
{file = "Pillow-9.0.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:b5b3f092fe345c03bca1e0b687dfbb39364b21ebb8ba90e3fa707374b7915204"}, {file = "Pillow-9.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8782189c796eff29dbb37dd87afa4ad4d40fc90b2742704f94812851b725964b"},
{file = "Pillow-9.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:335ace1a22325395c4ea88e00ba3dc89ca029bd66bd5a3c382d53e44f0ccd77e"}, {file = "Pillow-9.1.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:463acf531f5d0925ca55904fa668bb3461c3ef6bc779e1d6d8a488092bdee378"},
{file = "Pillow-9.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db6d9fac65bd08cea7f3540b899977c6dee9edad959fa4eaf305940d9cbd861c"}, {file = "Pillow-9.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f42364485bfdab19c1373b5cd62f7c5ab7cc052e19644862ec8f15bb8af289e"},
{file = "Pillow-9.0.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f154d173286a5d1863637a7dcd8c3437bb557520b01bddb0be0258dcb72696b5"}, {file = "Pillow-9.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3fddcdb619ba04491e8f771636583a7cc5a5051cd193ff1aa1ee8616d2a692c5"},
{file = "Pillow-9.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d4b1341ac07ae07eb2cc682f459bec932a380c3b122f5540432d8977e64eae"}, {file = "Pillow-9.1.0-cp38-cp38-win32.whl", hash = "sha256:4fe29a070de394e449fd88ebe1624d1e2d7ddeed4c12e0b31624561b58948d9a"},
{file = "Pillow-9.0.1-cp38-cp38-win32.whl", hash = "sha256:effb7749713d5317478bb3acb3f81d9d7c7f86726d41c1facca068a04cf5bb4c"}, {file = "Pillow-9.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:c24f718f9dd73bb2b31a6201e6db5ea4a61fdd1d1c200f43ee585fc6dcd21b34"},
{file = "Pillow-9.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:7f7609a718b177bf171ac93cea9fd2ddc0e03e84d8fa4e887bdfc39671d46b00"}, {file = "Pillow-9.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fb89397013cf302f282f0fc998bb7abf11d49dcff72c8ecb320f76ea6e2c5717"},
{file = "Pillow-9.0.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:80ca33961ced9c63358056bd08403ff866512038883e74f3a4bf88ad3eb66838"}, {file = "Pillow-9.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c870193cce4b76713a2b29be5d8327c8ccbe0d4a49bc22968aa1e680930f5581"},
{file = "Pillow-9.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1c3c33ac69cf059bbb9d1a71eeaba76781b450bc307e2291f8a4764d779a6b28"}, {file = "Pillow-9.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69e5ddc609230d4408277af135c5b5c8fe7a54b2bdb8ad7c5100b86b3aab04c6"},
{file = "Pillow-9.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12875d118f21cf35604176872447cdb57b07126750a33748bac15e77f90f1f9c"}, {file = "Pillow-9.1.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35be4a9f65441d9982240e6966c1eaa1c654c4e5e931eaf580130409e31804d4"},
{file = "Pillow-9.0.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:514ceac913076feefbeaf89771fd6febde78b0c4c1b23aaeab082c41c694e81b"}, {file = "Pillow-9.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82283af99c1c3a5ba1da44c67296d5aad19f11c535b551a5ae55328a317ce331"},
{file = "Pillow-9.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3c5c79ab7dfce6d88f1ba639b77e77a17ea33a01b07b99840d6ed08031cb2a7"}, {file = "Pillow-9.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a325ac71914c5c043fa50441b36606e64a10cd262de12f7a179620f579752ff8"},
{file = "Pillow-9.0.1-cp39-cp39-win32.whl", hash = "sha256:718856856ba31f14f13ba885ff13874be7fefc53984d2832458f12c38205f7f7"}, {file = "Pillow-9.1.0-cp39-cp39-win32.whl", hash = "sha256:a598d8830f6ef5501002ae85c7dbfcd9c27cc4efc02a1989369303ba85573e58"},
{file = "Pillow-9.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:f25ed6e28ddf50de7e7ea99d7a976d6a9c415f03adcaac9c41ff6ff41b6d86ac"}, {file = "Pillow-9.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:0c51cb9edac8a5abd069fd0758ac0a8bfe52c261ee0e330f363548aca6893595"},
{file = "Pillow-9.0.1-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:011233e0c42a4a7836498e98c1acf5e744c96a67dd5032a6f666cc1fb97eab97"}, {file = "Pillow-9.1.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a336a4f74baf67e26f3acc4d61c913e378e931817cd1e2ef4dfb79d3e051b481"},
{file = "Pillow-9.0.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:253e8a302a96df6927310a9d44e6103055e8fb96a6822f8b7f514bb7ef77de56"}, {file = "Pillow-9.1.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb1b89b11256b5b6cad5e7593f9061ac4624f7651f7a8eb4dfa37caa1dfaa4d0"},
{file = "Pillow-9.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6295f6763749b89c994fcb6d8a7f7ce03c3992e695f89f00b741b4580b199b7e"}, {file = "Pillow-9.1.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:255c9d69754a4c90b0ee484967fc8818c7ff8311c6dddcc43a4340e10cd1636a"},
{file = "Pillow-9.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a9f44cd7e162ac6191491d7249cceb02b8116b0f7e847ee33f739d7cb1ea1f70"}, {file = "Pillow-9.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5a3ecc026ea0e14d0ad7cd990ea7f48bfcb3eb4271034657dc9d06933c6629a7"},
{file = "Pillow-9.0.1.tar.gz", hash = "sha256:6c8bc8238a7dfdaf7a75f5ec5a663f4173f8c367e5a39f87e720495e1eed75fa"}, {file = "Pillow-9.1.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5b0ff59785d93b3437c3703e3c64c178aabada51dea2a7f2c5eccf1bcf565a3"},
{file = "Pillow-9.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7110ec1701b0bf8df569a7592a196c9d07c764a0a74f65471ea56816f10e2c8"},
{file = "Pillow-9.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:8d79c6f468215d1a8415aa53d9868a6b40c4682165b8cb62a221b1baa47db458"},
{file = "Pillow-9.1.0.tar.gz", hash = "sha256:f401ed2bbb155e1ade150ccc63db1a4f6c1909d3d378f7d1235a44e90d75fb97"},
] ]
platformdirs = [ platformdirs = [
{file = "platformdirs-2.5.1-py3-none-any.whl", hash = "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227"}, {file = "platformdirs-2.5.1-py3-none-any.whl", hash = "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227"},
@ -1954,8 +1971,8 @@ pytest = [
{file = "pytest-7.1.1.tar.gz", hash = "sha256:841132caef6b1ad17a9afde46dc4f6cfa59a05f9555aae5151f73bdf2820ca63"}, {file = "pytest-7.1.1.tar.gz", hash = "sha256:841132caef6b1ad17a9afde46dc4f6cfa59a05f9555aae5151f73bdf2820ca63"},
] ]
pytest-base-url = [ pytest-base-url = [
{file = "pytest-base-url-1.4.2.tar.gz", hash = "sha256:7f1f32e08c2ee751e59e7f5880235b46e83496adc5cba5a01ca218c6fe81333d"}, {file = "pytest-base-url-2.0.0.tar.gz", hash = "sha256:e1e88a4fd221941572ccdcf3bf6c051392d2f8b6cef3e0bc7da95abec4b5346e"},
{file = "pytest_base_url-1.4.2-py2.py3-none-any.whl", hash = "sha256:8b6523a1a3af73c317bdae97b722dfb55a7336733d1ad411eb4a4931347ba77a"}, {file = "pytest_base_url-2.0.0-py3-none-any.whl", hash = "sha256:ed36fd632c32af9f1c08f2c2835dcf42ca8fcd097d6ed44a09f253d365ad8297"},
] ]
pytest-black = [ pytest-black = [
{file = "pytest-black-0.3.12.tar.gz", hash = "sha256:1d339b004f764d6cd0f06e690f6dd748df3d62e6fe1a692d6a5500ac2c5b75a5"}, {file = "pytest-black-0.3.12.tar.gz", hash = "sha256:1d339b004f764d6cd0f06e690f6dd748df3d62e6fe1a692d6a5500ac2c5b75a5"},
@ -2008,8 +2025,8 @@ recommonmark = [
{file = "recommonmark-0.7.1.tar.gz", hash = "sha256:bdb4db649f2222dcd8d2d844f0006b958d627f732415d399791ee436a3686d67"}, {file = "recommonmark-0.7.1.tar.gz", hash = "sha256:bdb4db649f2222dcd8d2d844f0006b958d627f732415d399791ee436a3686d67"},
] ]
redis = [ redis = [
{file = "redis-4.2.0-py3-none-any.whl", hash = "sha256:3cbe235cea80b9c9991b397567aa2d65eb4e6fb09787f61d227ae82eb4eb50b4"}, {file = "redis-4.2.1-py3-none-any.whl", hash = "sha256:69d05fac17bf3f43937afbb775c536eb516bd21355a4f17d59a966f4a531ce71"},
{file = "redis-4.2.0.tar.gz", hash = "sha256:6758d01dec81af191b98a35cce3402675d115456584c39b500ab485a5e386bbb"}, {file = "redis-4.2.1.tar.gz", hash = "sha256:fe45513881229dbee610620b9e0817b1f48c47ba635870320fd44a712204bbdd"},
] ]
requests = [ requests = [
{file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"}, {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"},
@ -2043,8 +2060,8 @@ sortedcontainers = [
{file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"},
] ]
sphinx = [ sphinx = [
{file = "Sphinx-4.4.0-py3-none-any.whl", hash = "sha256:5da895959511473857b6d0200f56865ed62c31e8f82dd338063b84ec022701fe"}, {file = "Sphinx-4.5.0-py3-none-any.whl", hash = "sha256:ebf612653238bcc8f4359627a9b7ce44ede6fdd75d9d30f68255c7383d3a6226"},
{file = "Sphinx-4.4.0.tar.gz", hash = "sha256:6caad9786055cb1fa22b4a365c1775816b876f91966481765d7d50e9f0dd35cc"}, {file = "Sphinx-4.5.0.tar.gz", hash = "sha256:7bf8ca9637a4ee15af412d1a1d9689fec70523a68ca9bb9127c2f3eeb344e2e6"},
] ]
sphinx-bootstrap-theme = [ sphinx-bootstrap-theme = [
{file = "sphinx-bootstrap-theme-0.8.1.tar.gz", hash = "sha256:683e3b735448dadd0149f76edecf95ff4bd9157787e9e77e0d048ca6f1d680df"}, {file = "sphinx-bootstrap-theme-0.8.1.tar.gz", hash = "sha256:683e3b735448dadd0149f76edecf95ff4bd9157787e9e77e0d048ca6f1d680df"},
@ -2165,16 +2182,16 @@ typed-ast = [
{file = "typed_ast-1.5.2.tar.gz", hash = "sha256:525a2d4088e70a9f75b08b3f87a51acc9cde640e19cc523c7e41aa355564ae27"}, {file = "typed_ast-1.5.2.tar.gz", hash = "sha256:525a2d4088e70a9f75b08b3f87a51acc9cde640e19cc523c7e41aa355564ae27"},
] ]
types-freezegun = [ types-freezegun = [
{file = "types-freezegun-1.1.7.tar.gz", hash = "sha256:e9d1327e98c6caa8f65de0018ded274347e8e34198d59aa9a5c24ad9265d5e5e"}, {file = "types-freezegun-1.1.8.tar.gz", hash = "sha256:f4bb08c54aa46816c77a1b5c7a2a54f5393c3ce58e7d4002e67f9081b411e921"},
{file = "types_freezegun-1.1.7-py3-none-any.whl", hash = "sha256:efa02341ad35e4f24b3346d09b60332e967586a5bc495a56b1c9c927b4c788b6"}, {file = "types_freezegun-1.1.8-py3-none-any.whl", hash = "sha256:59dd99a6d168bdb5bf884fda6daebd68c35bc86383df183cf182abc6dfcbb7b7"},
] ]
types-pytz = [ types-pytz = [
{file = "types-pytz-2021.3.6.tar.gz", hash = "sha256:74547fd90d8d8ab4f1eedf3a344a7d186d97486973895f81221a712e1e2cd993"}, {file = "types-pytz-2021.3.6.tar.gz", hash = "sha256:74547fd90d8d8ab4f1eedf3a344a7d186d97486973895f81221a712e1e2cd993"},
{file = "types_pytz-2021.3.6-py3-none-any.whl", hash = "sha256:6805c72d51118923c5bf98633c39593d5b464d2ab49a803440e2d7ab6b8920df"}, {file = "types_pytz-2021.3.6-py3-none-any.whl", hash = "sha256:6805c72d51118923c5bf98633c39593d5b464d2ab49a803440e2d7ab6b8920df"},
] ]
types-requests = [ types-requests = [
{file = "types-requests-2.27.15.tar.gz", hash = "sha256:2d371183c535208d2cc8fe7473d9b49c344c7077eb70302eb708638fb86086a8"}, {file = "types-requests-2.27.16.tar.gz", hash = "sha256:c8010c18b291a7efb60b1452dbe12530bc25693dd657e70c62803fcdc4bffe9b"},
{file = "types_requests-2.27.15-py3-none-any.whl", hash = "sha256:77d09182a68e447e9e8b0ffc21abf54618b96f07689dffbb6a41cf0356542969"}, {file = "types_requests-2.27.16-py3-none-any.whl", hash = "sha256:2437a5f4d16c0c8bd7539a8126d492b7aeb41e6cda670d76b286c7f83a658d42"},
] ]
types-urllib3 = [ types-urllib3 = [
{file = "types-urllib3-1.26.11.tar.gz", hash = "sha256:24d64e441168851eb05f1d022de18ae31558f5649c8f1117e384c2e85e31315b"}, {file = "types-urllib3-1.26.11.tar.gz", hash = "sha256:24d64e441168851eb05f1d022de18ae31558f5649c8f1117e384c2e85e31315b"},
@ -2184,13 +2201,17 @@ typing-extensions = [
{file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"},
{file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"},
] ]
ua-parser = [
{file = "ua-parser-0.10.0.tar.gz", hash = "sha256:47b1782ed130d890018d983fac37c2a80799d9e0b9c532e734c67cf70f185033"},
{file = "ua_parser-0.10.0-py2.py3-none-any.whl", hash = "sha256:46ab2e383c01dbd2ab284991b87d624a26a08f72da4d7d413f5bfab8b9036f8a"},
]
urllib3 = [ urllib3 = [
{file = "urllib3-1.26.9-py2.py3-none-any.whl", hash = "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14"}, {file = "urllib3-1.26.9-py2.py3-none-any.whl", hash = "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14"},
{file = "urllib3-1.26.9.tar.gz", hash = "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"}, {file = "urllib3-1.26.9.tar.gz", hash = "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"},
] ]
werkzeug = [ werkzeug = [
{file = "Werkzeug-2.0.3-py3-none-any.whl", hash = "sha256:1421ebfc7648a39a5c58c601b154165d05cf47a3cd0ccb70857cbdacf6c8f2b8"}, {file = "Werkzeug-2.1.1-py3-none-any.whl", hash = "sha256:3c5493ece8268fecdcdc9c0b112211acd006354723b280d643ec732b6d4063d6"},
{file = "Werkzeug-2.0.3.tar.gz", hash = "sha256:b863f8ff057c522164b6067c9e28b041161b4be5ba4d0daceeaa50a163822d3c"}, {file = "Werkzeug-2.1.1.tar.gz", hash = "sha256:f8e89a20aeabbe8a893c24a461d3ee5dad2123b05cc6abd73ceed01d39c3ae74"},
] ]
wrapt = [ wrapt = [
{file = "wrapt-1.14.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:5a9a1889cc01ed2ed5f34574c90745fab1dd06ec2eee663e8ebeefe363e8efd7"}, {file = "wrapt-1.14.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:5a9a1889cc01ed2ed5f34574c90745fab1dd06ec2eee663e8ebeefe363e8efd7"},

View File

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "fittrackee" name = "fittrackee"
version = "0.6.1" version = "0.6.2"
description = "Self-hosted outdoor workout/activity tracker" description = "Self-hosted outdoor workout/activity tracker"
authors = ["SamR1"] authors = ["SamR1"]
license = "AGPL-3.0" license = "AGPL-3.0"
@ -24,9 +24,9 @@ exclude = ["fittrackee/tests"]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.7" python = "^3.7"
dramatiq = {version = "^1.12.3", extras = ["redis"]} dramatiq = {version = "^1.13", extras = ["redis"]}
flask = "^2.0" flask = "^2.1"
flask-bcrypt = "^0.7.1" flask-bcrypt = "^1.0"
flask-dramatiq = "^0.6.0" flask-dramatiq = "^0.6.0"
flask-migrate = "^3.1" flask-migrate = "^3.1"
gpxpy = "=1.3.4" gpxpy = "=1.3.4"
@ -40,9 +40,10 @@ shortuuid = "^1.0.8"
staticmap = "^0.5.4" staticmap = "^0.5.4"
SQLAlchemy = "1.4.32" SQLAlchemy = "1.4.32"
pyOpenSSL = "^22.0" pyOpenSSL = "^22.0"
ua-parser = "^0.10.0"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
black = "^22.1" black = "^22.3"
freezegun = "^1.2" freezegun = "^1.2"
mypy = "^0.942" mypy = "^0.942"
pytest = "^7.1" pytest = "^7.1"
@ -58,7 +59,7 @@ sphinxcontrib-httpdomain = "^1.7"
types-pytz = "^2021.3" types-pytz = "^2021.3"
types-requests = "^2.27" types-requests = "^2.27"
types-freezegun = "^1.1" types-freezegun = "^1.1"
Sphinx = "^4.4.0" Sphinx = "^4.5"
[tool.poetry.scripts] [tool.poetry.scripts]
fittrackee = 'fittrackee.__main__:main' fittrackee = 'fittrackee.__main__:main'