Merge branch 'release-v0.5.2'

This commit is contained in:
Sam 2021-12-19 16:20:12 +01:00
commit 7e7140d1e5
87 changed files with 1731 additions and 1576 deletions

View File

@ -1,5 +1,18 @@
# Change log
## Version 0.5.2 (2021/12/19)
### Issues Closed
#### New Features
* [#123](https://github.com/SamR1/FitTrackee/issues/123) - Allow user to reset preferences for a sport
* [#121](https://github.com/SamR1/FitTrackee/issues/121) - Add activity : snowshoes
In this release 2 issue were closed.
**Note:** This release contains database migration.
## Version 0.5.1 (2021/11/30)
### Issues Closed

View File

@ -11,6 +11,8 @@ build-client: lint-client
check-all: lint-all type-check test-python test-client
check-python: lint-python type-check test-python
clean:
rm -rf .mypy_cache
rm -rf .pytest_cache

View File

@ -1 +1 @@
0.5.1
0.5.2

View File

@ -1,4 +1,4 @@
# 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.
config: 756b383fe5a7ccedd8d0e56488a7df86
config: b9ebd39b84b07095312c3faada429e8c
tags: 645f666f9bcd5a90fca523b33c5a78b7

Binary file not shown.

Before

Width:  |  Height:  |  Size: 536 KiB

After

Width:  |  Height:  |  Size: 536 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 353 KiB

After

Width:  |  Height:  |  Size: 353 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: 71 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 103 KiB

View File

@ -10,6 +10,7 @@ Authentication
auth.edit_user,
auth.edit_user_preferences,
auth.edit_user_sport_preferences,
auth.reset_user_sport_preferences,
auth.edit_picture,
auth.del_picture,
auth.request_password_reset,

View File

@ -1,5 +1,18 @@
# Change log
## Version 0.5.2 (2021/12/19)
### Issues Closed
#### New Features
* [#123](https://github.com/SamR1/FitTrackee/issues/123) - Allow user to reset preferences for a sport
* [#121](https://github.com/SamR1/FitTrackee/issues/121) - Add activity : snowshoes
In this release 2 issue were closed.
**Note:** This release contains database migration.
## Version 0.5.1 (2021/11/30)
### Issues Closed

View File

@ -61,11 +61,13 @@ Workouts
- Running
- Skiing (Alpine) (**new in 0.5.0**)
- Skiing (Cross Country) (**new in 0.5.0**)
- Snowshoes (**new in 0.5.2**)
- Trail (**new in 0.5.0**)
- Walking
- (*new in 0.5.0*) Stopped speed threshold used by `gpxpy <https://github.com/tkrajina/gpxpy>`_ is not the default one for the following sports (0.1 km/h instead of 1 km/h):
- Hiking
- Skiing (Cross Country)
- Snowshoes
- Trail
- Walking

View File

@ -1,6 +1,6 @@
var DOCUMENTATION_OPTIONS = {
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
VERSION: '0.5.1',
VERSION: '0.5.2',
LANGUAGE: 'None',
COLLAPSE_INDEX: false,
BUILDER: 'html',

View File

@ -5,7 +5,7 @@
<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/" />
<title>Authentication &#8212; FitTrackee 0.5.1
<title>Authentication &#8212; FitTrackee 0.5.2
documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button>
<a class="navbar-brand" href="../index.html">
FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.5.1
<span class="navbar-text navbar-version pull-left"><b>0.5.2
</b></span>
</div>
@ -686,6 +686,54 @@
<li><p>invalid token, please log in again</p></li>
</ul>
</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5">404 Not Found</a></span> <ul>
<li><p>sport does not exist</p></li>
</ul>
</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.1">500 Internal Server Error</a></span> error, please try again or contact the administrator</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="http delete">
<dt class="sig sig-object http" id="delete--api-auth-profile-reset-sports-(sport_id)">
<span class="sig-name descname"><span class="pre">DELETE</span> </span><span class="sig-name descname"><span class="pre">/api/auth/profile/reset/sports/</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="pre">sport_id</span></em><span class="sig-paren">)</span><a class="headerlink" href="#delete--api-auth-profile-reset-sports-(sport_id)" title="Permalink to this definition"></a></dt>
<dd><p>reset authenticated user preferences for a given sport</p>
<p><strong>Example request</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="nf">DELETE</span> <span class="nn">/api/auth/profile/reset/sports/1</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
</pre></div>
</div>
<p><strong>Example response</strong>:</p>
<div class="highlight-http notranslate"><div class="highlight"><pre><span></span><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">204</span> <span class="ne">OK</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/json</span>
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>sport_id</strong> (<em>string</em>) sport id</p></li>
</ul>
</dd>
<dt class="field-even">Request Headers</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul>
</dd>
<dt class="field-odd">Status Codes</dt>
<dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5">204 No Content</a></span> user preferences deleted</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
<li><p>provide a valid auth token</p></li>
<li><p>signature expired, please log in again</p></li>
<li><p>invalid token, please log in again</p></li>
</ul>
</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5">404 Not Found</a></span> <ul>
<li><p>sport does not exist</p></li>
</ul>
</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.1">500 Internal Server Error</a></span> error, please try again or contact the administrator</p></li>
</ul>
</dd>

View File

@ -5,7 +5,7 @@
<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/" />
<title>Configuration &#8212; FitTrackee 0.5.1
<title>Configuration &#8212; FitTrackee 0.5.2
documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button>
<a class="navbar-brand" href="../index.html">
FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.5.1
<span class="navbar-text navbar-version pull-left"><b>0.5.2
</b></span>
</div>
@ -148,7 +148,7 @@
<span class="nt">&quot;max_zip_file_size&quot;</span><span class="p">:</span> <span class="mi">10485760</span><span class="p">,</span>
<span class="nt">&quot;max_users&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="nt">&quot;map_attribution&quot;</span><span class="p">:</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="nt">&quot;version&quot;</span><span class="p">:</span> <span class="s2">&quot;0.5.1&quot;</span>
<span class="nt">&quot;version&quot;</span><span class="p">:</span> <span class="s2">&quot;0.5.2&quot;</span>
<span class="p">},</span>
<span class="nt">&quot;status&quot;</span><span class="p">:</span> <span class="s2">&quot;success&quot;</span>
<span class="p">}</span>
@ -191,13 +191,8 @@
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dt class="field-odd">Request JSON Object</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
</ul>
</dd>
<dt class="field-even">Request JSON Object</dt>
<dd class="field-even"><ul class="simple">
<li><p><strong>gpx_limit_import</strong> (<em>integer</em>) max number of files in zip archive</p></li>
<li><p><strong>is_registration_enabled</strong> (<em>boolean</em>) is registration enabled ?</p></li>
<li><p><strong>max_single_file_size</strong> (<em>integer</em>) max size of a single file</p></li>
@ -205,13 +200,13 @@
<li><p><strong>max_users</strong> (<em>integer</em>) max users allowed to register on instance</p></li>
</ul>
</dd>
<dt class="field-odd">Request Headers</dt>
<dd class="field-odd"><ul class="simple">
<dt class="field-even">Request Headers</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul>
</dd>
<dt class="field-even">Status Codes</dt>
<dd class="field-even"><ul class="simple">
<dt class="field-odd">Status Codes</dt>
<dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>

View File

@ -5,7 +5,7 @@
<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/" />
<title>API documentation &#8212; FitTrackee 0.5.1
<title>API documentation &#8212; FitTrackee 0.5.2
documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button>
<a class="navbar-brand" href="../index.html">
FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.5.1
<span class="navbar-text navbar-version pull-left"><b>0.5.2
</b></span>
</div>

View File

@ -5,7 +5,7 @@
<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/" />
<title>Records &#8212; FitTrackee 0.5.1
<title>Records &#8212; FitTrackee 0.5.2
documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button>
<a class="navbar-brand" href="../index.html">
FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.5.1
<span class="navbar-text navbar-version pull-left"><b>0.5.2
</b></span>
</div>
@ -212,18 +212,13 @@
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dt class="field-odd">Request Headers</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
</ul>
</dd>
<dt class="field-even">Request Headers</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul>
</dd>
<dt class="field-odd">Status Codes</dt>
<dd class="field-odd"><ul class="simple">
<dt class="field-even">Status Codes</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
<li><p>provide a valid auth token</p></li>

View File

@ -5,7 +5,7 @@
<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/" />
<title>Sports &#8212; FitTrackee 0.5.1
<title>Sports &#8212; FitTrackee 0.5.2
documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button>
<a class="navbar-brand" href="../index.html">
FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.5.1
<span class="navbar-text navbar-version pull-left"><b>0.5.2
</b></span>
</div>
@ -270,18 +270,13 @@
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dt class="field-odd">Request Headers</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
</ul>
</dd>
<dt class="field-even">Request Headers</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul>
</dd>
<dt class="field-odd">Status Codes</dt>
<dd class="field-odd"><ul class="simple">
<dt class="field-even">Status Codes</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
<li><p>provide a valid auth token</p></li>
@ -368,7 +363,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>sport_id</strong> (<em>integer</em>) sport id</p></li>
</ul>
</dd>
@ -444,7 +438,6 @@ Authenticated user must be an admin</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>sport_id</strong> (<em>integer</em>) sport id</p></li>
</ul>
</dd>

View File

@ -5,7 +5,7 @@
<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/" />
<title>Statistics &#8212; FitTrackee 0.5.1
<title>Statistics &#8212; FitTrackee 0.5.2
documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button>
<a class="navbar-brand" href="../index.html">
FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.5.1
<span class="navbar-text navbar-version pull-left"><b>0.5.2
</b></span>
</div>
@ -206,7 +206,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>user_name</strong> (<em>integer</em>) user name</p></li>
</ul>
</dd>
@ -321,7 +320,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>user_name</strong> (<em>integer</em>) user name</p></li>
</ul>
</dd>
@ -378,18 +376,13 @@
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dt class="field-odd">Request Headers</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
</ul>
</dd>
<dt class="field-even">Request Headers</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul>
</dd>
<dt class="field-odd">Status Codes</dt>
<dd class="field-odd"><ul class="simple">
<dt class="field-even">Status Codes</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
<li><p>provide a valid auth token</p></li>

View File

@ -5,7 +5,7 @@
<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/" />
<title>Users &#8212; FitTrackee 0.5.1
<title>Users &#8212; FitTrackee 0.5.2
documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button>
<a class="navbar-brand" href="../index.html">
FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.5.1
<span class="navbar-text navbar-version pull-left"><b>0.5.2
</b></span>
</div>
@ -242,13 +242,8 @@
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dt class="field-odd">Query Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
</ul>
</dd>
<dt class="field-even">Query Parameters</dt>
<dd class="field-even"><ul class="simple">
<li><p><strong>page</strong> (<em>integer</em>) page if using pagination (default: 1)</p></li>
<li><p><strong>per_page</strong> (<em>integer</em>) number of users per page (default: 10, max: 50)</p></li>
<li><p><strong>q</strong> (<em>string</em>) query on user name</p></li>
@ -257,13 +252,13 @@
<li><p><strong>order</strong> (<em>string</em>) sorting order (default: <code class="docutils literal notranslate"><span class="pre">asc</span></code>)</p></li>
</ul>
</dd>
<dt class="field-odd">Request Headers</dt>
<dd class="field-odd"><ul class="simple">
<dt class="field-even">Request Headers</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul>
</dd>
<dt class="field-even">Status Codes</dt>
<dd class="field-even"><ul class="simple">
<dt class="field-odd">Status Codes</dt>
<dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
<li><p>provide a valid auth token</p></li>
@ -361,7 +356,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>user_name</strong> (<em>integer</em>) user name</p></li>
</ul>
</dd>
@ -507,7 +501,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>user_name</strong> (<em>string</em>) user name</p></li>
</ul>
</dd>
@ -561,7 +554,6 @@ one admin</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>user_name</strong> (<em>string</em>) user name</p></li>
</ul>
</dd>

View File

@ -5,7 +5,7 @@
<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/" />
<title>Workouts &#8212; FitTrackee 0.5.1
<title>Workouts &#8212; FitTrackee 0.5.2
documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button>
<a class="navbar-brand" href="../index.html">
FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.5.1
<span class="navbar-text navbar-version pull-left"><b>0.5.2
</b></span>
</div>
@ -241,13 +241,8 @@
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dt class="field-odd">Query Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
</ul>
</dd>
<dt class="field-even">Query Parameters</dt>
<dd class="field-even"><ul class="simple">
<li><p><strong>page</strong> (<em>integer</em>) page if using pagination (default: 1)</p></li>
<li><p><strong>per_page</strong> (<em>integer</em>) number of workouts per page
(default: 5, max: 100)</p></li>
@ -265,13 +260,13 @@
<li><p><strong>order</strong> (<em>string</em>) sorting order (default: <code class="docutils literal notranslate"><span class="pre">desc</span></code>)</p></li>
</ul>
</dd>
<dt class="field-odd">Request Headers</dt>
<dd class="field-odd"><ul class="simple">
<dt class="field-even">Request Headers</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul>
</dd>
<dt class="field-even">Status Codes</dt>
<dd class="field-even"><ul class="simple">
<dt class="field-odd">Status Codes</dt>
<dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1">200 OK</a></span> success</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
<li><p>provide a valid auth token</p></li>
@ -355,7 +350,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
</ul>
</dd>
@ -405,7 +399,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
</ul>
</dd>
@ -478,7 +471,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
</ul>
</dd>
@ -551,7 +543,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
<li><p><strong>segment_id</strong> (<em>integer</em>) segment id</p></li>
</ul>
@ -603,7 +594,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
<li><p><strong>segment_id</strong> (<em>integer</em>) segment id</p></li>
</ul>
@ -708,7 +698,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
</ul>
</dd>
@ -820,24 +809,19 @@
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dt class="field-odd">Form Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
</ul>
</dd>
<dt class="field-even">Form Parameters</dt>
<dd class="field-even"><ul class="simple">
<li><p><strong>file</strong> gpx file (allowed extensions: .gpx, .zip)</p></li>
<li><p><strong>data</strong> sport id and notes (example: <code class="docutils literal notranslate"><span class="pre">{&quot;sport_id&quot;:</span> <span class="pre">1,</span> <span class="pre">&quot;notes&quot;:</span> <span class="pre">&quot;&quot;}</span></code>)</p></li>
</ul>
</dd>
<dt class="field-odd">Request Headers</dt>
<dd class="field-odd"><ul class="simple">
<dt class="field-even">Request Headers</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul>
</dd>
<dt class="field-even">Status Codes</dt>
<dd class="field-even"><ul class="simple">
<dt class="field-odd">Status Codes</dt>
<dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.2">201 Created</a></span> workout created</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> <ul>
<li><p>invalid payload</p></li>
@ -948,13 +932,8 @@
</pre></div>
</div>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dt class="field-odd">Request JSON Object</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
</ul>
</dd>
<dt class="field-even">Request JSON Object</dt>
<dd class="field-even"><ul class="simple">
<li><p><strong>workout_date</strong> (<em>string</em>) workout date (format: <code class="docutils literal notranslate"><span class="pre">%Y-%m-%d</span> <span class="pre">%H:%M</span></code>)</p></li>
<li><p><strong>distance</strong> (<em>float</em>) workout distance in km</p></li>
<li><p><strong>duration</strong> (<em>integer</em>) workout duration in seconds</p></li>
@ -963,13 +942,13 @@
<li><p><strong>title</strong> (<em>string</em>) workout title</p></li>
</ul>
</dd>
<dt class="field-odd">Request Headers</dt>
<dd class="field-odd"><ul class="simple">
<dt class="field-even">Request Headers</dt>
<dd class="field-even"><ul class="simple">
<li><p><span><a class="reference external" href="https://tools.ietf.org/html/rfc7235#section-4.2">Authorization</a></span> OAuth 2.0 Bearer Token</p></li>
</ul>
</dd>
<dt class="field-even">Status Codes</dt>
<dd class="field-even"><ul class="simple">
<dt class="field-odd">Status Codes</dt>
<dd class="field-odd"><ul class="simple">
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.2">201 Created</a></span> workout created</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">400 Bad Request</a></span> invalid payload</p></li>
<li><p><span><a class="reference external" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">401 Unauthorized</a></span> <ul>
@ -1075,7 +1054,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
</ul>
</dd>
@ -1131,7 +1109,6 @@
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>auth_user_id</strong> (<em>integer</em>) authenticate user id (from JSON Web Token)</p></li>
<li><p><strong>workout_short_id</strong> (<em>string</em>) workout short id</p></li>
</ul>
</dd>

View File

@ -5,7 +5,7 @@
<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/" />
<title>Change log &#8212; FitTrackee 0.5.1
<title>Change log &#8212; FitTrackee 0.5.2
documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
@ -39,7 +39,7 @@
</button>
<a class="navbar-brand" href="index.html">
FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.5.1
<span class="navbar-text navbar-version pull-left"><b>0.5.2
</b></span>
</div>
@ -77,16 +77,23 @@
role="menu"
aria-labelledby="dLabelLocalToc"><ul>
<li><a class="reference internal" href="#">Change log</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="#version-0-5-2-2021-12-19">Version 0.5.2 (2021/12/19)</a><ul>
<li><a class="reference internal" href="#issues-closed">Issues Closed</a><ul>
<li><a class="reference internal" href="#new-features">New Features</a></li>
</ul>
</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="#version-0-5-1-2021-11-30">Version 0.5.1 (2021/11/30)</a><ul>
<li><a class="reference internal" href="#id1">Issues Closed</a><ul>
<li><a class="reference internal" href="#id2">New Features</a></li>
</ul>
</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="#id3">Issues Closed</a><ul>
<li><a class="reference internal" href="#id4">New Features</a></li>
<li><a class="reference internal" href="#bugs-fixed">Bugs Fixed</a></li>
<li><a class="reference internal" href="#misc">Misc</a></li>
</ul>
@ -95,137 +102,137 @@
</ul>
</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="#id3">Issues Closed</a><ul>
<li><a class="reference internal" href="#id4">New Features</a></li>
<li><a class="reference internal" href="#id5">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="#id6">Issues Closed</a><ul>
<li><a class="reference internal" href="#id5">Issues Closed</a><ul>
<li><a class="reference internal" href="#id6">New Features</a></li>
<li><a class="reference internal" href="#id7">Bugs Fixed</a></li>
</ul>
</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="#version-0-4-8-2021-07-03">Version 0.4.8 (2021/07/03)</a><ul>
<li><a class="reference internal" href="#id8">Issues Closed</a><ul>
<li><a class="reference internal" href="#id9">Bugs Fixed</a></li>
</ul>
</li>
<li><a class="reference internal" href="#id10">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="#id10">Issues Closed</a><ul>
<li><a class="reference internal" href="#id11">Bugs Fixed</a></li>
</ul>
</li>
<li><a class="reference internal" href="#id12">Misc</a></li>
</ul>
</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="#id11">Issues Closed</a><ul>
<li><a class="reference internal" href="#id12">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="#id13">Issues Closed</a><ul>
<li><a class="reference internal" href="#id14">Bugs Fixed</a></li>
</ul>
</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="#version-0-4-5-2021-02-17">Version 0.4.5 (2021/02/17)</a><ul>
<li><a class="reference internal" href="#id15">Issues Closed</a><ul>
<li><a class="reference internal" href="#id16">Bugs Fixed</a></li>
</ul>
</li>
<li><a class="reference internal" href="#id17">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="#id17">Issues Closed</a><ul>
<li><a class="reference internal" href="#id18">Bugs Fixed</a></li>
</ul>
</li>
<li><a class="reference internal" href="#id19">Misc</a></li>
</ul>
</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="#id18">Issues Closed</a><ul>
<li><a class="reference internal" href="#id19">New Features</a></li>
<li><a class="reference internal" href="#id20">Bugs Fixed</a></li>
<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="#id22">Bugs Fixed</a></li>
</ul>
</li>
</ul>
</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="#id21">Misc</a></li>
<li><a class="reference internal" href="#id23">Misc</a></li>
</ul>
</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="#id22">Issues Closed</a><ul>
<li><a class="reference internal" href="#id23">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="#id24">Issues Closed</a><ul>
<li><a class="reference internal" href="#id25">New Features</a></li>
</ul>
</li>
</ul>
</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="#id26">Issues Closed</a><ul>
<li><a class="reference internal" href="#id27">New Features</a></li>
</ul>
</li>
</ul>
</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="#id28">Issues Closed</a><ul>
<li><a class="reference internal" href="#id29">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="#id28">Misc</a></li>
<li><a class="reference internal" href="#id30">Misc</a></li>
</ul>
</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="#id29">Issues Closed</a><ul>
<li><a class="reference internal" href="#id30">Bugs Fixed</a></li>
<li><a class="reference internal" href="#id31">Issues Closed</a><ul>
<li><a class="reference internal" href="#id32">Bugs Fixed</a></li>
</ul>
</li>
</ul>
</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="#id31">Issues Closed</a><ul>
<li><a class="reference internal" href="#id32">New Features</a></li>
<li><a class="reference internal" href="#id33">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="#id34">Issues Closed</a><ul>
<li><a class="reference internal" href="#id33">Issues Closed</a><ul>
<li><a class="reference internal" href="#id34">New Features</a></li>
<li><a class="reference internal" href="#id35">Bugs Fixed</a></li>
</ul>
</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="#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="#id36">Issues Closed</a><ul>
<li><a class="reference internal" href="#id37">New Features</a></li>
<li><a class="reference internal" href="#id38">Bugs Fixed</a></li>
<li><a class="reference internal" href="#id37">Bugs Fixed</a></li>
</ul>
</li>
<li><a class="reference internal" href="#id39">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="#id38">Issues Closed</a><ul>
<li><a class="reference internal" href="#id39">New Features</a></li>
<li><a class="reference internal" href="#id40">Bugs Fixed</a></li>
</ul>
</li>
<li><a class="reference internal" href="#id41">Misc</a></li>
</ul>
</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="#id40">Issues Closed</a><ul>
<li><a class="reference internal" href="#id41">New Features</a></li>
<li><a class="reference internal" href="#id42">Issues Closed</a><ul>
<li><a class="reference internal" href="#id43">New Features</a></li>
</ul>
</li>
<li><a class="reference internal" href="#id42">Misc</a></li>
<li><a class="reference internal" href="#id44">Misc</a></li>
</ul>
</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="#id43">Issues Closed</a><ul>
<li><a class="reference internal" href="#id44">New Features</a></li>
<li><a class="reference internal" href="#id45">Bugs Fixed</a></li>
<li><a class="reference internal" href="#id45">Issues Closed</a><ul>
<li><a class="reference internal" href="#id46">New Features</a></li>
<li><a class="reference internal" href="#id47">Bugs Fixed</a></li>
</ul>
</li>
</ul>
</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="#id46">Issues Closed</a><ul>
<li><a class="reference internal" href="#id47">New Features</a></li>
<li><a class="reference internal" href="#id48">Issues Closed</a><ul>
<li><a class="reference internal" href="#id49">New Features</a></li>
</ul>
</li>
</ul>
@ -277,13 +284,27 @@
<section id="change-log">
<h1>Change log<a class="headerlink" href="#change-log" title="Permalink to this headline"></a></h1>
<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>
<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>
<section id="issues-closed">
<h3>Issues Closed<a class="headerlink" href="#issues-closed" title="Permalink to this headline"></a></h3>
<section id="new-features">
<h4>New Features<a class="headerlink" href="#new-features" title="Permalink to this headline"></a></h4>
<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/121">#121</a> - Add activity : snowshoes</p></li>
</ul>
<p>In this release 2 issue were closed.<br /><strong>Note:</strong> This release contains database migration.</p>
</section>
</section>
</section>
<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>
<section id="id1">
<h3>Issues Closed<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h3>
<section id="id2">
<h4>New Features<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/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/5">#5</a> - Display a chart with average speed</p></li>
@ -294,10 +315,10 @@
</section>
<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>
<section id="id1">
<h3>Issues Closed<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h3>
<section id="id2">
<h4>New Features<a class="headerlink" href="#id2" title="Permalink to this headline"></a></h4>
<section id="id3">
<h3>Issues Closed<a class="headerlink" href="#id3" title="Permalink to this headline"></a></h3>
<section id="id4">
<h4>New Features<a class="headerlink" href="#id4" title="Permalink to this headline"></a></h4>
<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/91">#91</a> - Display elevation chart with min and max altitude of workout</p></li>
@ -336,17 +357,17 @@
</section>
<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>
<section id="id3">
<h3>Issues Closed<a class="headerlink" href="#id3" title="Permalink to this headline"></a></h3>
<section id="id4">
<h4>New Features<a class="headerlink" href="#id4" title="Permalink to this headline"></a></h4>
<section id="id5">
<h3>Issues Closed<a class="headerlink" href="#id5" title="Permalink to this headline"></a></h3>
<section id="id6">
<h4>New Features<a class="headerlink" href="#id6" title="Permalink to this headline"></a></h4>
<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/81">#81</a> - display remaining characters in textarea</p></li>
</ul>
</section>
<section id="id5">
<h4>Bugs Fixed<a class="headerlink" href="#id5" title="Permalink to this headline"></a></h4>
<section id="id7">
<h4>Bugs Fixed<a class="headerlink" href="#id7" title="Permalink to this headline"></a></h4>
<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/80">#80</a> - can not save notes with control characters</p></li>
@ -357,10 +378,10 @@
</section>
<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>
<section id="id6">
<h3>Issues Closed<a class="headerlink" href="#id6" title="Permalink to this headline"></a></h3>
<section id="id7">
<h4>Bugs Fixed<a class="headerlink" href="#id7" title="Permalink to this headline"></a></h4>
<section id="id8">
<h3>Issues Closed<a class="headerlink" href="#id8" title="Permalink to this headline"></a></h3>
<section id="id9">
<h4>Bugs Fixed<a class="headerlink" href="#id9" title="Permalink to this headline"></a></h4>
<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>
</ul>
@ -370,17 +391,17 @@
</section>
<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>
<section id="id8">
<h3>Issues Closed<a class="headerlink" href="#id8" title="Permalink to this headline"></a></h3>
<section id="id9">
<h4>Bugs Fixed<a class="headerlink" href="#id9" title="Permalink to this headline"></a></h4>
<section id="id10">
<h3>Issues Closed<a class="headerlink" href="#id10" title="Permalink to this headline"></a></h3>
<section id="id11">
<h4>Bugs Fixed<a class="headerlink" href="#id11" title="Permalink to this headline"></a></h4>
<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>
</ul>
</section>
</section>
<section id="id10">
<h3>Misc<a class="headerlink" href="#id10" title="Permalink to this headline"></a></h3>
<section id="id12">
<h3>Misc<a class="headerlink" href="#id12" title="Permalink to this headline"></a></h3>
<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>
</ul>
@ -389,10 +410,10 @@
</section>
<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>
<section id="id11">
<h3>Issues Closed<a class="headerlink" href="#id11" title="Permalink to this headline"></a></h3>
<section id="id12">
<h4>Bugs Fixed<a class="headerlink" href="#id12" title="Permalink to this headline"></a></h4>
<section id="id13">
<h3>Issues Closed<a class="headerlink" href="#id13" title="Permalink to this headline"></a></h3>
<section id="id14">
<h4>Bugs Fixed<a class="headerlink" href="#id14" title="Permalink to this headline"></a></h4>
<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/71">#71</a> - max size or max number of files must be greater than 0</p></li>
@ -404,10 +425,10 @@
</section>
<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>
<section id="id13">
<h3>Issues Closed<a class="headerlink" href="#id13" title="Permalink to this headline"></a></h3>
<section id="id14">
<h4>Bugs Fixed<a class="headerlink" href="#id14" title="Permalink to this headline"></a></h4>
<section id="id15">
<h3>Issues Closed<a class="headerlink" href="#id15" title="Permalink to this headline"></a></h3>
<section id="id16">
<h4>Bugs Fixed<a class="headerlink" href="#id16" title="Permalink to this headline"></a></h4>
<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/64">#64</a> - Only 50 workouts per month shown in calendar</p></li>
@ -418,17 +439,17 @@
</section>
<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>
<section id="id15">
<h3>Issues Closed<a class="headerlink" href="#id15" title="Permalink to this headline"></a></h3>
<section id="id16">
<h4>Bugs Fixed<a class="headerlink" href="#id16" title="Permalink to this headline"></a></h4>
<section id="id17">
<h3>Issues Closed<a class="headerlink" href="#id17" title="Permalink to this headline"></a></h3>
<section id="id18">
<h4>Bugs Fixed<a class="headerlink" href="#id18" title="Permalink to this headline"></a></h4>
<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>
</ul>
</section>
</section>
<section id="id17">
<h3>Misc<a class="headerlink" href="#id17" title="Permalink to this headline"></a></h3>
<section id="id19">
<h3>Misc<a class="headerlink" href="#id19" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Refactoring before introducing new features.</p></li>
<li><p>Add docker files for evaluation purposes.</p></li>
@ -438,16 +459,16 @@
</section>
<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>
<section id="id18">
<h3>Issues Closed<a class="headerlink" href="#id18" title="Permalink to this headline"></a></h3>
<section id="id19">
<h4>New Features<a class="headerlink" href="#id19" title="Permalink to this headline"></a></h4>
<section id="id20">
<h3>Issues Closed<a class="headerlink" href="#id20" title="Permalink to this headline"></a></h3>
<section id="id21">
<h4>New Features<a class="headerlink" href="#id21" title="Permalink to this headline"></a></h4>
<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>
</ul>
</section>
<section id="id20">
<h4>Bugs Fixed<a class="headerlink" href="#id20" title="Permalink to this headline"></a></h4>
<section id="id22">
<h4>Bugs Fixed<a class="headerlink" href="#id22" title="Permalink to this headline"></a></h4>
<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>
</ul>
@ -457,18 +478,18 @@
</section>
<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>
<section id="id21">
<h3>Misc<a class="headerlink" href="#id21" title="Permalink to this headline"></a></h3>
<section id="id23">
<h3>Misc<a class="headerlink" href="#id23" title="Permalink to this headline"></a></h3>
<p>No new features in this release, only some refactorings before introducing
new features.</p>
</section>
</section>
<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>
<section id="id22">
<h3>Issues Closed<a class="headerlink" href="#id22" title="Permalink to this headline"></a></h3>
<section id="id23">
<h4>New Features<a class="headerlink" href="#id23" title="Permalink to this headline"></a></h4>
<section id="id24">
<h3>Issues Closed<a class="headerlink" href="#id24" title="Permalink to this headline"></a></h3>
<section id="id25">
<h4>New Features<a class="headerlink" href="#id25" title="Permalink to this headline"></a></h4>
<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>
</ul>
@ -484,10 +505,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>),
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>
<section id="id24">
<h3>Issues Closed<a class="headerlink" href="#id24" title="Permalink to this headline"></a></h3>
<section id="id25">
<h4>New Features<a class="headerlink" href="#id25" title="Permalink to this headline"></a></h4>
<section id="id26">
<h3>Issues Closed<a class="headerlink" href="#id26" title="Permalink to this headline"></a></h3>
<section id="id27">
<h4>New Features<a class="headerlink" href="#id27" title="Permalink to this headline"></a></h4>
<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/53">#53</a> - Simplify FitTrackee installation</p></li>
@ -503,10 +524,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>in order to send emails, Redis is now a mandatory dependency</p></li>
</ul>
<section id="id26">
<h3>Issues Closed<a class="headerlink" href="#id26" title="Permalink to this headline"></a></h3>
<section id="id27">
<h4>New Features<a class="headerlink" href="#id27" title="Permalink to this headline"></a></h4>
<section id="id28">
<h3>Issues Closed<a class="headerlink" href="#id28" title="Permalink to this headline"></a></h3>
<section id="id29">
<h4>New Features<a class="headerlink" href="#id29" title="Permalink to this headline"></a></h4>
<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/17">#17</a> - A user can delete his account</p></li>
@ -518,8 +539,8 @@ see <a class="reference external" href="https://samr1.github.io/FitTrackee/insta
</section>
<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>
<section id="id28">
<h3>Misc<a class="headerlink" href="#id28" title="Permalink to this headline"></a></h3>
<section id="id30">
<h3>Misc<a class="headerlink" href="#id30" title="Permalink to this headline"></a></h3>
<p>This version contains minor fix and improvements on client side:</p>
<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>
@ -532,10 +553,10 @@ add URL interceptors to simplify routes definition</p></li>
</section>
<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>
<section id="id29">
<h3>Issues Closed<a class="headerlink" href="#id29" title="Permalink to this headline"></a></h3>
<section id="id30">
<h4>Bugs Fixed<a class="headerlink" href="#id30" title="Permalink to this headline"></a></h4>
<section id="id31">
<h3>Issues Closed<a class="headerlink" href="#id31" title="Permalink to this headline"></a></h3>
<section id="id32">
<h4>Bugs Fixed<a class="headerlink" href="#id32" title="Permalink to this headline"></a></h4>
<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/46">#46</a> - calendar cannot display more than 5 or 6 activities on the same day</p></li>
@ -546,17 +567,17 @@ add URL interceptors to simplify routes definition</p></li>
</section>
<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>
<section id="id31">
<h3>Issues Closed<a class="headerlink" href="#id31" title="Permalink to this headline"></a></h3>
<section id="id32">
<h4>New Features<a class="headerlink" href="#id32" title="Permalink to this headline"></a></h4>
<section id="id33">
<h3>Issues Closed<a class="headerlink" href="#id33" title="Permalink to this headline"></a></h3>
<section id="id34">
<h4>New Features<a class="headerlink" href="#id34" title="Permalink to this headline"></a></h4>
<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/40">#40</a> - Localize FitTrackee (i18n)</p></li>
</ul>
</section>
<section id="id33">
<h4>Bugs Fixed<a class="headerlink" href="#id33" title="Permalink to this headline"></a></h4>
<section id="id35">
<h4>Bugs Fixed<a class="headerlink" href="#id35" title="Permalink to this headline"></a></h4>
<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>
</ul>
@ -566,10 +587,10 @@ add URL interceptors to simplify routes definition</p></li>
</section>
<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>
<section id="id34">
<h3>Issues Closed<a class="headerlink" href="#id34" title="Permalink to this headline"></a></h3>
<section id="id35">
<h4>Bugs Fixed<a class="headerlink" href="#id35" title="Permalink to this headline"></a></h4>
<section id="id36">
<h3>Issues Closed<a class="headerlink" href="#id36" title="Permalink to this headline"></a></h3>
<section id="id37">
<h4>Bugs Fixed<a class="headerlink" href="#id37" title="Permalink to this headline"></a></h4>
<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>
</ul>
@ -579,10 +600,10 @@ add URL interceptors to simplify routes definition</p></li>
</section>
<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>
<section id="id36">
<h3>Issues Closed<a class="headerlink" href="#id36" title="Permalink to this headline"></a></h3>
<section id="id37">
<h4>New Features<a class="headerlink" href="#id37" title="Permalink to this headline"></a></h4>
<section id="id38">
<h3>Issues Closed<a class="headerlink" href="#id38" title="Permalink to this headline"></a></h3>
<section id="id39">
<h4>New Features<a class="headerlink" href="#id39" title="Permalink to this headline"></a></h4>
<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/14">#14</a> - Display segments informations</p></li>
@ -593,15 +614,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>
</ul>
</section>
<section id="id38">
<h4>Bugs Fixed<a class="headerlink" href="#id38" title="Permalink to this headline"></a></h4>
<section id="id40">
<h4>Bugs Fixed<a class="headerlink" href="#id40" title="Permalink to this headline"></a></h4>
<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>
</ul>
</section>
</section>
<section id="id39">
<h3>Misc<a class="headerlink" href="#id39" title="Permalink to this headline"></a></h3>
<section id="id41">
<h3>Misc<a class="headerlink" href="#id41" title="Permalink to this headline"></a></h3>
<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>
</ul>
@ -610,17 +631,17 @@ add URL interceptors to simplify routes definition</p></li>
</section>
<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>
<section id="id40">
<h3>Issues Closed<a class="headerlink" href="#id40" title="Permalink to this headline"></a></h3>
<section id="id41">
<h4>New Features<a class="headerlink" href="#id41" title="Permalink to this headline"></a></h4>
<section id="id42">
<h3>Issues Closed<a class="headerlink" href="#id42" title="Permalink to this headline"></a></h3>
<section id="id43">
<h4>New Features<a class="headerlink" href="#id43" title="Permalink to this headline"></a></h4>
<ul class="simple">
<li><p><a class="reference external" href="https://github.com/SamR1/Fittrackee/issues/13">#13</a> - Detailed statistics</p></li>
</ul>
</section>
</section>
<section id="id42">
<h3>Misc<a class="headerlink" href="#id42" title="Permalink to this headline"></a></h3>
<section id="id44">
<h3>Misc<a class="headerlink" href="#id44" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Update dependencies</p></li>
</ul>
@ -629,17 +650,17 @@ add URL interceptors to simplify routes definition</p></li>
</section>
<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>
<section id="id43">
<h3>Issues Closed<a class="headerlink" href="#id43" title="Permalink to this headline"></a></h3>
<section id="id44">
<h4>New Features<a class="headerlink" href="#id44" title="Permalink to this headline"></a></h4>
<section id="id45">
<h3>Issues Closed<a class="headerlink" href="#id45" title="Permalink to this headline"></a></h3>
<section id="id46">
<h4>New Features<a class="headerlink" href="#id46" title="Permalink to this headline"></a></h4>
<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/22">#22</a> - Add a total on current month statistics</p></li>
</ul>
</section>
<section id="id45">
<h4>Bugs Fixed<a class="headerlink" href="#id45" title="Permalink to this headline"></a></h4>
<section id="id47">
<h4>Bugs Fixed<a class="headerlink" href="#id47" title="Permalink to this headline"></a></h4>
<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/29">#29</a> - Pause duration calculation with segments</p></li>
@ -688,10 +709,10 @@ add URL interceptors to simplify routes definition</p></li>
<li><p>no administration for now</p></li>
</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>
<section id="id46">
<h3>Issues Closed<a class="headerlink" href="#id46" title="Permalink to this headline"></a></h3>
<section id="id47">
<h4>New Features<a class="headerlink" href="#id47" title="Permalink to this headline"></a></h4>
<section id="id48">
<h3>Issues Closed<a class="headerlink" href="#id48" title="Permalink to this headline"></a></h3>
<section id="id49">
<h4>New Features<a class="headerlink" href="#id49" title="Permalink to this headline"></a></h4>
<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/10">#10</a> - Add a note to an activity</p></li>

View File

@ -5,7 +5,7 @@
<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/" />
<title>Features &#8212; FitTrackee 0.5.1
<title>Features &#8212; FitTrackee 0.5.2
documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button>
<a class="navbar-brand" href="index.html">
FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.5.1
<span class="navbar-text navbar-version pull-left"><b>0.5.2
</b></span>
</div>
@ -214,6 +214,7 @@
<li><p>Running</p></li>
<li><p>Skiing (Alpine) (<strong>new in 0.5.0</strong>)</p></li>
<li><p>Skiing (Cross Country) (<strong>new in 0.5.0</strong>)</p></li>
<li><p>Snowshoes (<strong>new in 0.5.2</strong>)</p></li>
<li><p>Trail (<strong>new in 0.5.0</strong>)</p></li>
<li><p>Walking</p></li>
</ul>
@ -224,6 +225,7 @@
<dt>(<em>new in 0.5.0</em>) Stopped speed threshold used by <a class="reference external" href="https://github.com/tkrajina/gpxpy">gpxpy</a> is not the default one for the following sports (0.1 km/h instead of 1 km/h):</dt><dd><ul>
<li><p>Hiking</p></li>
<li><p>Skiing (Cross Country)</p></li>
<li><p>Snowshoes</p></li>
<li><p>Trail</p></li>
<li><p>Walking</p></li>
</ul>

View File

@ -4,7 +4,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Index &#8212; FitTrackee 0.5.1
<title>Index &#8212; FitTrackee 0.5.2
documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
@ -37,7 +37,7 @@
</button>
<a class="navbar-brand" href="index.html">
FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.5.1
<span class="navbar-text navbar-version pull-left"><b>0.5.2
</b></span>
</div>

View File

@ -4,7 +4,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>HTTP Routing Table &#8212; FitTrackee 0.5.1
<title>HTTP Routing Table &#8212; FitTrackee 0.5.2
documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
@ -44,7 +44,7 @@
</button>
<a class="navbar-brand" href="index.html">
FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.5.1
<span class="navbar-text navbar-version pull-left"><b>0.5.2
</b></span>
</div>
@ -290,6 +290,11 @@
<td>
<a href="api/auth.html#delete--api-auth-picture"><code class="xref">DELETE /api/auth/picture</code></a></td><td>
<em></em></td></tr>
<tr>
<td></td>
<td>
<a href="api/auth.html#delete--api-auth-profile-reset-sports-(sport_id)"><code class="xref">DELETE /api/auth/profile/reset/sports/(sport_id)</code></a></td><td>
<em></em></td></tr>
<tr>
<td></td>
<td>

View File

@ -5,7 +5,7 @@
<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/" />
<title>FitTrackee &#8212; FitTrackee 0.5.1
<title>FitTrackee &#8212; FitTrackee 0.5.2
documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
@ -39,7 +39,7 @@
</button>
<a class="navbar-brand" href="#">
FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.5.1
<span class="navbar-text navbar-version pull-left"><b>0.5.2
</b></span>
</div>
@ -185,6 +185,7 @@ Map</a>.</div>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="changelog.html">Change log</a><ul>
<li class="toctree-l2"><a class="reference internal" href="changelog.html#version-0-5-2-2021-12-19">Version 0.5.2 (2021/12/19)</a></li>
<li class="toctree-l2"><a class="reference internal" href="changelog.html#version-0-5-1-2021-11-30">Version 0.5.1 (2021/11/30)</a></li>
<li class="toctree-l2"><a class="reference internal" href="changelog.html#version-0-5-0-2021-11-14">Version 0.5.0 (2021/11/14)</a></li>
<li class="toctree-l2"><a class="reference internal" href="changelog.html#version-0-4-9-2021-07-16">Version 0.4.9 (2021/07/16)</a></li>

View File

@ -5,7 +5,7 @@
<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/" />
<title>Installation &#8212; FitTrackee 0.5.1
<title>Installation &#8212; FitTrackee 0.5.2
documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button>
<a class="navbar-brand" href="index.html">
FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.5.1
<span class="navbar-text navbar-version pull-left"><b>0.5.2
</b></span>
</div>

Binary file not shown.

View File

@ -4,7 +4,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Search &#8212; FitTrackee 0.5.1
<title>Search &#8212; FitTrackee 0.5.2
documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
@ -43,7 +43,7 @@
</button>
<a class="navbar-brand" href="index.html">
FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.5.1
<span class="navbar-text navbar-version pull-left"><b>0.5.2
</b></span>
</div>

File diff suppressed because one or more lines are too long

View File

@ -5,7 +5,7 @@
<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/" />
<title>Administrator &#8212; FitTrackee 0.5.1
<title>Administrator &#8212; FitTrackee 0.5.2
documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button>
<a class="navbar-brand" href="../index.html">
FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.5.1
<span class="navbar-text navbar-version pull-left"><b>0.5.2
</b></span>
</div>

View File

@ -5,7 +5,7 @@
<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/" />
<title>Troubleshooting &#8212; FitTrackee 0.5.1
<title>Troubleshooting &#8212; FitTrackee 0.5.2
documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button>
<a class="navbar-brand" href="../index.html">
FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.5.1
<span class="navbar-text navbar-version pull-left"><b>0.5.2
</b></span>
</div>

View File

@ -5,7 +5,7 @@
<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/" />
<title>User &#8212; FitTrackee 0.5.1
<title>User &#8212; FitTrackee 0.5.2
documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/bootstrap-sphinx.css" />
@ -40,7 +40,7 @@
</button>
<a class="navbar-brand" href="../index.html">
FitTrackee</a>
<span class="navbar-text navbar-version pull-left"><b>0.5.1
<span class="navbar-text navbar-version pull-left"><b>0.5.2
</b></span>
</div>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 536 KiB

After

Width:  |  Height:  |  Size: 536 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 353 KiB

After

Width:  |  Height:  |  Size: 353 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: 71 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 103 KiB

View File

@ -10,6 +10,7 @@ Authentication
auth.edit_user,
auth.edit_user_preferences,
auth.edit_user_sport_preferences,
auth.reset_user_sport_preferences,
auth.edit_picture,
auth.del_picture,
auth.request_password_reset,

View File

@ -61,11 +61,13 @@ Workouts
- Running
- Skiing (Alpine) (**new in 0.5.0**)
- Skiing (Cross Country) (**new in 0.5.0**)
- Snowshoes (**new in 0.5.2**)
- Trail (**new in 0.5.0**)
- Walking
- (*new in 0.5.0*) Stopped speed threshold used by `gpxpy <https://github.com/tkrajina/gpxpy>`_ is not the default one for the following sports (0.1 km/h instead of 1 km/h):
- Hiking
- Skiing (Cross Country)
- Snowshoes
- Trail
- Walking

View File

@ -11,7 +11,7 @@ from flask_sqlalchemy import SQLAlchemy
from fittrackee.emails.email import Email
VERSION = __version__ = '0.5.1'
VERSION = __version__ = '0.5.2'
db = SQLAlchemy()
bcrypt = Bcrypt()
migrate = Migrate()

View File

@ -10,6 +10,7 @@ from fittrackee.responses import (
handle_error_and_return_response,
)
from fittrackee.users.decorators import authenticate_as_admin
from fittrackee.users.models import User
from .models import AppConfig
from .utils import update_app_config_from_database, verify_app_config
@ -44,7 +45,7 @@ def get_application_config() -> Union[Dict, HttpResponse]:
"max_zip_file_size": 10485760,
"max_users": 0,
"map_attribution": "&copy; <a href=http://www.openstreetmap.org/copyright>OpenStreetMap</a> contributors"
"version": "0.5.1"
"version": "0.5.2"
},
"status": "success"
}
@ -64,7 +65,7 @@ def get_application_config() -> Union[Dict, HttpResponse]:
@config_blueprint.route('/config', methods=['PATCH'])
@authenticate_as_admin
def update_application_config(auth_user_id: int) -> Union[Dict, HttpResponse]:
def update_application_config(auth_user: User) -> Union[Dict, HttpResponse]:
"""
Update Application config
@ -95,8 +96,6 @@ def update_application_config(auth_user_id: int) -> Union[Dict, HttpResponse]:
"status": "success"
}
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:<json integer gpx_limit_import: max number of files in zip archive
:<json boolean is_registration_enabled: is registration enabled ?
:<json integer max_single_file_size: max size of a single file

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><link href="/static/css/admin.e77f8b26.css" rel="prefetch"><link href="/static/css/profile.8b668068.css" rel="prefetch"><link href="/static/css/reset.fc19709e.css" rel="prefetch"><link href="/static/css/statistics.2afdc8a9.css" rel="prefetch"><link href="/static/css/workouts.5ffd5cc1.css" rel="prefetch"><link href="/static/js/admin.5f46d0fe.js" rel="prefetch"><link href="/static/js/chunk-2d0c9189.c81458cc.js" rel="prefetch"><link href="/static/js/chunk-2d0cf391.020c75ea.js" rel="prefetch"><link href="/static/js/chunk-2d0da8f3.c8c3e7e8.js" rel="prefetch"><link href="/static/js/chunk-2d2248b6.d84473c1.js" rel="prefetch"><link href="/static/js/chunk-2d22523a.4b710d99.js" rel="prefetch"><link href="/static/js/profile.d25975e2.js" rel="prefetch"><link href="/static/js/reset.ca898ebe.js" rel="prefetch"><link href="/static/js/statistics.d03ca304.js" rel="prefetch"><link href="/static/js/workouts.ad3402f3.js" rel="prefetch"><link href="/static/css/app.c2c4db70.css" rel="preload" as="style"><link href="/static/js/app.be515752.js" rel="preload" as="script"><link href="/static/js/chunk-vendors.d6c4f7de.js" rel="preload" as="script"><link href="/static/css/app.c2c4db70.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><script src="/static/js/chunk-vendors.d6c4f7de.js"></script><script src="/static/js/app.be515752.js"></script></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><link href="/static/css/admin.e77f8b26.css" rel="prefetch"><link href="/static/css/profile.8b668068.css" rel="prefetch"><link href="/static/css/reset.fc19709e.css" rel="prefetch"><link href="/static/css/statistics.2afdc8a9.css" rel="prefetch"><link href="/static/css/workouts.5ffd5cc1.css" rel="prefetch"><link href="/static/js/admin.5f46d0fe.js" rel="prefetch"><link href="/static/js/chunk-2d0c9189.c81458cc.js" rel="prefetch"><link href="/static/js/chunk-2d0cf391.020c75ea.js" rel="prefetch"><link href="/static/js/chunk-2d0da8f3.c8c3e7e8.js" rel="prefetch"><link href="/static/js/chunk-2d2248b6.d84473c1.js" rel="prefetch"><link href="/static/js/chunk-2d22523a.4b710d99.js" rel="prefetch"><link href="/static/js/profile.d25975e2.js" rel="prefetch"><link href="/static/js/reset.ca898ebe.js" rel="prefetch"><link href="/static/js/statistics.d03ca304.js" rel="prefetch"><link href="/static/js/workouts.e3d575e0.js" rel="prefetch"><link href="/static/css/app.d45a3498.css" rel="preload" as="style"><link href="/static/js/app.82615f01.js" rel="preload" as="script"><link href="/static/js/chunk-vendors.b68629ef.js" rel="preload" as="script"><link href="/static/css/app.d45a3498.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><script src="/static/js/chunk-vendors.b68629ef.js"></script><script src="/static/js/app.82615f01.js"></script></body></html>

View File

@ -64,7 +64,7 @@ self.__precacheManifest = (self.__precacheManifest || []).concat([
"url": "/img/workouts/mountains.svg"
},
{
"revision": "33a95b48f126239891c717230e24d541",
"revision": "abe55a57f153488b08a952dd6e57f389",
"url": "/index.html"
},
{
@ -80,8 +80,8 @@ self.__precacheManifest = (self.__precacheManifest || []).concat([
"url": "/static/css/admin.e77f8b26.css"
},
{
"revision": "ee0ec8715f39d6fc0c2f",
"url": "/static/css/app.c2c4db70.css"
"revision": "1bd90ea525b6b37d9aaa",
"url": "/static/css/app.d45a3498.css"
},
{
"revision": "82c1118c918377daaa71a320ab8eea42",
@ -104,7 +104,7 @@ self.__precacheManifest = (self.__precacheManifest || []).concat([
"url": "/static/css/statistics.2afdc8a9.css"
},
{
"revision": "164e46d16f7d58980b74",
"revision": "839b1979e05d0b296f23",
"url": "/static/css/workouts.5ffd5cc1.css"
},
{
@ -192,8 +192,8 @@ self.__precacheManifest = (self.__precacheManifest || []).concat([
"url": "/static/js/admin.5f46d0fe.js"
},
{
"revision": "ee0ec8715f39d6fc0c2f",
"url": "/static/js/app.be515752.js"
"revision": "1bd90ea525b6b37d9aaa",
"url": "/static/js/app.82615f01.js"
},
{
"revision": "bd7d183c9f68e5f4027d",
@ -216,8 +216,8 @@ self.__precacheManifest = (self.__precacheManifest || []).concat([
"url": "/static/js/chunk-2d22523a.4b710d99.js"
},
{
"revision": "bfd9828f544921bd8a32",
"url": "/static/js/chunk-vendors.d6c4f7de.js"
"revision": "4389fa919b954132ecf5",
"url": "/static/js/chunk-vendors.b68629ef.js"
},
{
"revision": "00382d944a1bc6fca08b",
@ -232,7 +232,7 @@ self.__precacheManifest = (self.__precacheManifest || []).concat([
"url": "/static/js/statistics.d03ca304.js"
},
{
"revision": "164e46d16f7d58980b74",
"url": "/static/js/workouts.ad3402f3.js"
"revision": "839b1979e05d0b296f23",
"url": "/static/js/workouts.e3d575e0.js"
}
]);

View File

@ -14,7 +14,7 @@
importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js");
importScripts(
"/precache-manifest.075bb045c70c2ae156d071ec25ebc386.js"
"/precache-manifest.7ed432ba92f492c4803cc1589ff8a454.js"
);
workbox.core.setCacheNameDetails({prefix: "fittrackee_client"});

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

View File

@ -0,0 +1,33 @@
"""add snowshoes sport
Revision ID: ed409fd9db9d
Revises: 07188ca7620a
Create Date: 2021-12-19 09:09:37.531543
"""
from alembic import op
# revision identifiers, used by Alembic.
revision = 'ed409fd9db9d'
down_revision = '07188ca7620a'
branch_labels = None
depends_on = None
def upgrade():
op.execute(
"""
INSERT INTO sports (label, is_active, stopped_speed_threshold)
VALUES ('Snowshoes', True, 0.1)
"""
)
def downgrade():
op.execute(
"""
DELETE FROM sports
WHERE label = 'Snowshoes';
"""
)

View File

@ -7,7 +7,7 @@ import pytest
from flask import Flask
from freezegun import freeze_time
from fittrackee.users.models import User
from fittrackee.users.models import User, UserSportPreference
from fittrackee.users.utils_token import get_user_token
from fittrackee.workouts.models import Sport, Workout
@ -887,6 +887,7 @@ class TestUserSportPreferencesUpdate(ApiTestCaseMixin):
data = json.loads(response.data.decode())
assert response.status_code == 404
assert 'not found' in data['status']
assert 'sport does not exist' in data['message']
def test_it_returns_error_if_payload_contains_only_sport_id(
self, app: Flask, user_1: User, sport_1_cycling: Sport
@ -1017,6 +1018,58 @@ class TestUserSportPreferencesUpdate(ApiTestCaseMixin):
assert data['data']['stopped_speed_threshold'] == 0.5
class TestUserSportPreferencesReset(ApiTestCaseMixin):
def test_it_returns_error_if_sport_does_not_exist(
self, app: Flask, user_1: User
) -> None:
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.delete(
'/api/auth/profile/reset/sports/1',
headers=dict(Authorization=f'Bearer {auth_token}'),
)
assert response.status_code == 404
data = json.loads(response.data.decode())
assert 'not found' in data['status']
assert 'sport does not exist' in data['message']
def test_it_resets_sport_preferences(
self,
app: Flask,
user_1: User,
sport_1_cycling: Sport,
user_sport_1_preference: UserSportPreference,
) -> None:
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.delete(
f'/api/auth/profile/reset/sports/{sport_1_cycling.id}',
headers=dict(Authorization=f'Bearer {auth_token}'),
)
assert response.status_code == 204
assert (
UserSportPreference.query.filter_by(
user_id=user_1.id,
sport_id=sport_1_cycling.id,
).first()
is None
)
def test_it_does_not_raise_error_if_sport_preferences_do_not_exist(
self, app: Flask, user_1: User, sport_1_cycling: Sport
) -> None:
client, auth_token = self.get_test_client_and_auth_token(app)
response = client.delete(
f'/api/auth/profile/reset/sports/{sport_1_cycling.id}',
headers=dict(Authorization=f'Bearer {auth_token}'),
)
assert response.status_code == 204
class TestUserPicture(ApiTestCaseMixin):
def test_it_updates_user_picture(self, app: Flask, user_1: User) -> None:
client, auth_token = self.get_test_client_and_auth_token(app)

View File

@ -46,7 +46,7 @@ class TestStoppedSpeedThreshold:
) as gpx_track_segment_mock:
process_files(
auth_user_id=user_1.id,
auth_user=user_1,
folders=folders,
workout_data={'sport_id': sport_id},
workout_file=gpx_file_storage,
@ -76,7 +76,7 @@ class TestStoppedSpeedThreshold:
) as gpx_track_segment_mock:
process_files(
auth_user_id=user_1.id,
auth_user=user_1,
folders=folders,
workout_data={'sport_id': sport_1_cycling.id},
workout_file=gpx_file_storage,

View File

@ -11,10 +11,10 @@ from werkzeug.utils import secure_filename
from fittrackee import appLog, bcrypt, db
from fittrackee.responses import (
DataNotFoundErrorResponse,
ForbiddenErrorResponse,
HttpResponse,
InvalidPayloadErrorResponse,
NotFoundErrorResponse,
PayloadTooLargeErrorResponse,
UnauthorizedErrorResponse,
handle_error_and_return_response,
@ -224,7 +224,7 @@ def login_user() -> Union[Dict, HttpResponse]:
@auth_blueprint.route('/auth/logout', methods=['GET'])
@authenticate
def logout_user(auth_user_id: int) -> Union[Dict, HttpResponse]:
def logout_user(auth_user: User) -> Union[Dict, HttpResponse]:
"""
user logout
@ -274,7 +274,7 @@ def logout_user(auth_user_id: int) -> Union[Dict, HttpResponse]:
auth_token = auth_header.split(' ')[1]
resp = User.decode_auth_token(auth_token)
if isinstance(auth_user_id, str):
if isinstance(resp, str):
return UnauthorizedErrorResponse(resp)
return {
@ -286,7 +286,7 @@ def logout_user(auth_user_id: int) -> Union[Dict, HttpResponse]:
@auth_blueprint.route('/auth/profile', methods=['GET'])
@authenticate
def get_authenticated_user_profile(
auth_user_id: int,
auth_user: User,
) -> Union[Dict, HttpResponse]:
"""
get authenticated user info
@ -381,13 +381,12 @@ def get_authenticated_user_profile(
- invalid token, please log in again
"""
user = User.query.filter_by(id=auth_user_id).first()
return {'status': 'success', 'data': user.serialize()}
return {'status': 'success', 'data': auth_user.serialize()}
@auth_blueprint.route('/auth/profile/edit', methods=['POST'])
@authenticate
def edit_user(auth_user_id: int) -> Union[Dict, HttpResponse]:
def edit_user(auth_user: User) -> Union[Dict, HttpResponse]:
"""
edit authenticated user
@ -523,24 +522,23 @@ def edit_user(auth_user_id: int) -> Union[Dict, HttpResponse]:
).decode()
try:
user = User.query.filter_by(id=auth_user_id).first()
user.first_name = first_name
user.last_name = last_name
user.bio = bio
user.location = location
user.birth_date = (
auth_user.first_name = first_name
auth_user.last_name = last_name
auth_user.bio = bio
auth_user.location = location
auth_user.birth_date = (
datetime.datetime.strptime(birth_date, '%Y-%m-%d')
if birth_date
else None
)
if password is not None and password != '':
user.password = password
auth_user.password = password
db.session.commit()
return {
'status': 'success',
'message': 'user profile updated',
'data': user.serialize(),
'data': auth_user.serialize(),
}
# handler errors
@ -550,7 +548,7 @@ def edit_user(auth_user_id: int) -> Union[Dict, HttpResponse]:
@auth_blueprint.route('/auth/profile/edit/preferences', methods=['POST'])
@authenticate
def edit_user_preferences(auth_user_id: int) -> Union[Dict, HttpResponse]:
def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]:
"""
edit authenticated user preferences
@ -670,17 +668,16 @@ def edit_user_preferences(auth_user_id: int) -> Union[Dict, HttpResponse]:
weekm = post_data.get('weekm')
try:
user = User.query.filter_by(id=auth_user_id).first()
user.imperial_units = imperial_units
user.language = language
user.timezone = timezone
user.weekm = weekm
auth_user.imperial_units = imperial_units
auth_user.language = language
auth_user.timezone = timezone
auth_user.weekm = weekm
db.session.commit()
return {
'status': 'success',
'message': 'user preferences updated',
'data': user.serialize(),
'data': auth_user.serialize(),
}
# handler errors
@ -691,7 +688,7 @@ def edit_user_preferences(auth_user_id: int) -> Union[Dict, HttpResponse]:
@auth_blueprint.route('/auth/profile/edit/sports', methods=['POST'])
@authenticate
def edit_user_sport_preferences(
auth_user_id: int,
auth_user: User,
) -> Union[Dict, HttpResponse]:
"""
edit authenticated user sport preferences
@ -736,6 +733,8 @@ def edit_user_sport_preferences(
- provide a valid auth token
- signature expired, please log in again
- invalid token, please log in again
:statuscode 404:
- sport does not exist
:statuscode 500: error, please try again or contact the administrator
"""
@ -750,7 +749,7 @@ def edit_user_sport_preferences(
sport_id = post_data.get('sport_id')
sport = Sport.query.filter_by(id=sport_id).first()
if not sport:
return DataNotFoundErrorResponse('sports')
return NotFoundErrorResponse('sport does not exist')
color = post_data.get('color')
is_active = post_data.get('is_active')
@ -758,12 +757,12 @@ def edit_user_sport_preferences(
try:
user_sport = UserSportPreference.query.filter_by(
user_id=auth_user_id,
user_id=auth_user.id,
sport_id=sport_id,
).first()
if not user_sport:
user_sport = UserSportPreference(
user_id=auth_user_id,
user_id=auth_user.id,
sport_id=sport_id,
stopped_speed_threshold=sport.stopped_speed_threshold,
)
@ -790,9 +789,66 @@ def edit_user_sport_preferences(
return handle_error_and_return_response(e, db=db)
@auth_blueprint.route(
'/auth/profile/reset/sports/<sport_id>', methods=['DELETE']
)
@authenticate
def reset_user_sport_preferences(
auth_user: User, sport_id: int
) -> Union[Tuple[Dict, int], HttpResponse]:
"""
reset authenticated user preferences for a given sport
**Example request**:
.. sourcecode:: http
DELETE /api/auth/profile/reset/sports/1 HTTP/1.1
Content-Type: application/json
**Example response**:
.. sourcecode:: http
HTTP/1.1 204 OK
Content-Type: application/json
:param string sport_id: sport id
:reqheader Authorization: OAuth 2.0 Bearer Token
:statuscode 204: user preferences deleted
:statuscode 401:
- provide a valid auth token
- signature expired, please log in again
- invalid token, please log in again
:statuscode 404:
- sport does not exist
:statuscode 500: error, please try again or contact the administrator
"""
sport = Sport.query.filter_by(id=sport_id).first()
if not sport:
return NotFoundErrorResponse('sport does not exist')
try:
user_sport = UserSportPreference.query.filter_by(
user_id=auth_user.id,
sport_id=sport_id,
).first()
if user_sport:
db.session.delete(user_sport)
db.session.commit()
return {'status': 'no content'}, 204
# handler errors
except (exc.IntegrityError, exc.OperationalError) as e:
return handle_error_and_return_response(e, db=db)
@auth_blueprint.route('/auth/picture', methods=['POST'])
@authenticate
def edit_picture(auth_user_id: int) -> Union[Dict, HttpResponse]:
def edit_picture(auth_user: User) -> Union[Dict, HttpResponse]:
"""
update authenticated user picture
@ -848,23 +904,22 @@ def edit_picture(auth_user_id: int) -> Union[Dict, HttpResponse]:
file = request.files['file']
filename = secure_filename(file.filename) # type: ignore
dirpath = os.path.join(
current_app.config['UPLOAD_FOLDER'], 'pictures', str(auth_user_id)
current_app.config['UPLOAD_FOLDER'], 'pictures', str(auth_user.id)
)
if not os.path.exists(dirpath):
os.makedirs(dirpath)
absolute_picture_path = os.path.join(dirpath, filename)
relative_picture_path = os.path.join(
'pictures', str(auth_user_id), filename
'pictures', str(auth_user.id), filename
)
try:
user = User.query.filter_by(id=auth_user_id).first()
if user.picture is not None:
old_picture_path = get_absolute_file_path(user.picture)
if auth_user.picture is not None:
old_picture_path = get_absolute_file_path(auth_user.picture)
if os.path.isfile(get_absolute_file_path(old_picture_path)):
os.remove(old_picture_path)
file.save(absolute_picture_path)
user.picture = relative_picture_path
auth_user.picture = relative_picture_path
db.session.commit()
return {
'status': 'success',
@ -879,7 +934,7 @@ def edit_picture(auth_user_id: int) -> Union[Dict, HttpResponse]:
@auth_blueprint.route('/auth/picture', methods=['DELETE'])
@authenticate
def del_picture(auth_user_id: int) -> Union[Tuple[Dict, int], HttpResponse]:
def del_picture(auth_user: User) -> Union[Tuple[Dict, int], HttpResponse]:
"""
delete authenticated user picture
@ -908,11 +963,10 @@ def del_picture(auth_user_id: int) -> Union[Tuple[Dict, int], HttpResponse]:
"""
try:
user = User.query.filter_by(id=auth_user_id).first()
picture_path = get_absolute_file_path(user.picture)
picture_path = get_absolute_file_path(auth_user.picture)
if os.path.isfile(picture_path):
os.remove(picture_path)
user.picture = None
auth_user.picture = None
db.session.commit()
return {'status': 'no content'}, 204
except (exc.IntegrityError, ValueError) as e:

View File

@ -8,16 +8,22 @@ from fittrackee.responses import HttpResponse
from .utils import verify_user
def verify_auth_user(
f: Callable, verify_admin: bool, *args: Any, **kwargs: Any
) -> Union[Callable, HttpResponse]:
response_object, user = verify_user(request, verify_admin=verify_admin)
if response_object:
return response_object
return f(user, *args, **kwargs)
def authenticate(f: Callable) -> Callable:
@wraps(f)
def decorated_function(
*args: Any, **kwargs: Any
) -> Union[Callable, HttpResponse]:
verify_admin = False
response_object, resp = verify_user(request, verify_admin)
if response_object:
return response_object
return f(resp, *args, **kwargs)
return verify_auth_user(f, verify_admin, *args, **kwargs)
return decorated_function
@ -28,9 +34,6 @@ def authenticate_as_admin(f: Callable) -> Callable:
*args: Any, **kwargs: Any
) -> Union[Callable, HttpResponse]:
verify_admin = True
response_object, resp = verify_user(request, verify_admin)
if response_object:
return response_object
return f(resp, *args, **kwargs)
return verify_auth_user(f, verify_admin, *args, **kwargs)
return decorated_function

View File

@ -27,7 +27,7 @@ USER_PER_PAGE = 10
@users_blueprint.route('/users', methods=['GET'])
@authenticate
def get_users(auth_user_id: int) -> Dict:
def get_users(auth_user: User) -> Dict:
"""
Get all users
@ -144,8 +144,6 @@ def get_users(auth_user_id: int) -> Dict:
"status": "success"
}
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:query integer page: page if using pagination (default: 1)
:query integer per_page: number of users per page (default: 10, max: 50)
:query string q: query on user name
@ -219,7 +217,7 @@ def get_users(auth_user_id: int) -> Dict:
@users_blueprint.route('/users/<user_name>', methods=['GET'])
@authenticate
def get_single_user(
auth_user_id: int, user_name: str
auth_user: User, user_name: str
) -> Union[Dict, HttpResponse]:
"""
Get single user details
@ -306,7 +304,6 @@ def get_single_user(
"status": "success"
}
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:param integer user_name: user name
:reqheader Authorization: OAuth 2.0 Bearer Token
@ -371,9 +368,7 @@ def get_picture(user_name: str) -> Any:
@users_blueprint.route('/users/<user_name>', methods=['PATCH'])
@authenticate_as_admin
def update_user(
auth_user_id: int, user_name: str
) -> Union[Dict, HttpResponse]:
def update_user(auth_user: User, user_name: str) -> Union[Dict, HttpResponse]:
"""
Update user to add admin rights
@ -461,7 +456,6 @@ def update_user(
"status": "success"
}
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:param string user_name: user name
:<json boolean admin: does the user have administrator rights
@ -500,7 +494,7 @@ def update_user(
@users_blueprint.route('/users/<user_name>', methods=['DELETE'])
@authenticate
def delete_user(
auth_user_id: int, user_name: str
auth_user: User, user_name: str
) -> Union[Tuple[Dict, int], HttpResponse]:
"""
Delete a user account
@ -524,7 +518,6 @@ def delete_user(
HTTP/1.1 204 NO CONTENT
Content-Type: application/json
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:param string user_name: user name
:reqheader Authorization: OAuth 2.0 Bearer Token
@ -543,12 +536,11 @@ def delete_user(
"""
try:
auth_user = User.query.filter_by(id=auth_user_id).first()
user = User.query.filter_by(username=user_name).first()
if not user:
return UserNotFoundErrorResponse()
if user.id != auth_user_id and not auth_user.admin:
if user.id != auth_user.id and not auth_user.admin:
return ForbiddenErrorResponse()
if (
user.admin is True

View File

@ -12,14 +12,6 @@ from fittrackee.responses import (
from .models import User
def is_admin(user_id: int) -> bool:
"""
Return if user has admin rights
"""
user = User.query.filter_by(id=user_id).first()
return user.admin
def is_valid_email(email: str) -> bool:
"""
Return if email format is valid
@ -62,10 +54,10 @@ def register_controls(
def verify_user(
current_request: Request, verify_admin: bool
) -> Tuple[Optional[HttpResponse], Optional[int]]:
) -> Tuple[Optional[HttpResponse], Optional[User]]:
"""
Return user id, if the provided token is valid and if user has admin
rights if 'verify_admin' is True
Return authenticated user, if the provided token is valid and user has
admin rights if 'verify_admin' is True
"""
default_message = 'provide a valid auth token'
auth_header = current_request.headers.get('Authorization')
@ -78,9 +70,9 @@ def verify_user(
user = User.query.filter_by(id=resp).first()
if not user:
return UnauthorizedErrorResponse(default_message), None
if verify_admin and not is_admin(resp):
if verify_admin and not user.admin:
return ForbiddenErrorResponse(), None
return None, resp
return None, user
def can_view_workout(

View File

@ -3,6 +3,7 @@ from typing import Dict
from flask import Blueprint
from fittrackee.users.decorators import authenticate
from fittrackee.users.models import User
from .models import Record
@ -11,7 +12,7 @@ records_blueprint = Blueprint('records', __name__)
@records_blueprint.route('/records', methods=['GET'])
@authenticate
def get_records(auth_user_id: int) -> Dict:
def get_records(auth_user: User) -> Dict:
"""
Get all records for authenticated user.
@ -95,8 +96,6 @@ def get_records(auth_user_id: int) -> Dict:
"status": "success"
}
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:reqheader Authorization: OAuth 2.0 Bearer Token
:statuscode 200: success
@ -107,7 +106,7 @@ def get_records(auth_user_id: int) -> Dict:
"""
records = (
Record.query.filter_by(user_id=auth_user_id)
Record.query.filter_by(user_id=auth_user.id)
.order_by(Record.sport_id.asc(), Record.record_type.asc())
.all()
)

View File

@ -20,7 +20,7 @@ sports_blueprint = Blueprint('sports', __name__)
@sports_blueprint.route('/sports', methods=['GET'])
@authenticate
def get_sports(auth_user_id: int) -> Dict:
def get_sports(auth_user: User) -> Dict:
"""
Get all sports
@ -165,8 +165,6 @@ def get_sports(auth_user_id: int) -> Dict:
"status": "success"
}
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:reqheader Authorization: OAuth 2.0 Bearer Token
:statuscode 200: success
@ -176,16 +174,15 @@ def get_sports(auth_user_id: int) -> Dict:
- invalid token, please log in again
"""
user = User.query.filter_by(id=int(auth_user_id)).first()
sports = Sport.query.order_by(Sport.id).all()
sports_data = []
for sport in sports:
sport_preferences = UserSportPreference.query.filter_by(
user_id=user.id, sport_id=sport.id
user_id=auth_user.id, sport_id=sport.id
).first()
sports_data.append(
sport.serialize(
is_admin=user.admin,
is_admin=auth_user.admin,
sport_preferences=sport_preferences.serialize()
if sport_preferences
else None,
@ -199,7 +196,7 @@ def get_sports(auth_user_id: int) -> Dict:
@sports_blueprint.route('/sports/<int:sport_id>', methods=['GET'])
@authenticate
def get_sport(auth_user_id: int, sport_id: int) -> Union[Dict, HttpResponse]:
def get_sport(auth_user: User, sport_id: int) -> Union[Dict, HttpResponse]:
"""
Get a sport
@ -273,7 +270,6 @@ def get_sport(auth_user_id: int, sport_id: int) -> Union[Dict, HttpResponse]:
"status": "not found"
}
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:param integer sport_id: sport id
:reqheader Authorization: OAuth 2.0 Bearer Token
@ -286,18 +282,17 @@ def get_sport(auth_user_id: int, sport_id: int) -> Union[Dict, HttpResponse]:
:statuscode 404: sport not found
"""
user = User.query.filter_by(id=int(auth_user_id)).first()
sport = Sport.query.filter_by(id=sport_id).first()
if sport:
sport_preferences = UserSportPreference.query.filter_by(
user_id=user.id, sport_id=sport.id
user_id=auth_user.id, sport_id=sport.id
).first()
return {
'status': 'success',
'data': {
'sports': [
sport.serialize(
is_admin=user.admin,
is_admin=auth_user.admin,
sport_preferences=sport_preferences.serialize()
if sport_preferences
else None,
@ -310,9 +305,7 @@ def get_sport(auth_user_id: int, sport_id: int) -> Union[Dict, HttpResponse]:
@sports_blueprint.route('/sports/<int:sport_id>', methods=['PATCH'])
@authenticate_as_admin
def update_sport(
auth_user_id: int, sport_id: int
) -> Union[Dict, HttpResponse]:
def update_sport(auth_user: User, sport_id: int) -> Union[Dict, HttpResponse]:
"""
Update a sport
Authenticated user must be an admin
@ -364,7 +357,6 @@ def update_sport(
"status": "not found"
}
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:param integer sport_id: sport id
:<json string is_active: sport active status
@ -387,7 +379,6 @@ def update_sport(
return InvalidPayloadErrorResponse()
try:
user = User.query.filter_by(id=int(auth_user_id)).first()
sport = Sport.query.filter_by(id=sport_id).first()
if not sport:
return DataNotFoundErrorResponse('sports')
@ -395,14 +386,14 @@ def update_sport(
sport.is_active = sport_data.get('is_active')
db.session.commit()
sport_preferences = UserSportPreference.query.filter_by(
user_id=user.id, sport_id=sport.id
user_id=auth_user.id, sport_id=sport.id
).first()
return {
'status': 'success',
'data': {
'sports': [
sport.serialize(
is_admin=user.admin,
is_admin=auth_user.admin,
sport_preferences=sport_preferences.serialize()
if sport_preferences
else None,

View File

@ -179,7 +179,7 @@ def get_workouts(
@stats_blueprint.route('/stats/<user_name>/by_time', methods=['GET'])
@authenticate
def get_workouts_by_time(
auth_user_id: int, user_name: str
auth_user: User, user_name: str
) -> Union[Dict, HttpResponse]:
"""
Get workouts statistics for a user by time
@ -258,7 +258,6 @@ def get_workouts_by_time(
"status": "success"
}
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:param integer user_name: user name
:query string from: start date (format: ``%Y-%m-%d``)
@ -287,7 +286,7 @@ def get_workouts_by_time(
@stats_blueprint.route('/stats/<user_name>/by_sport', methods=['GET'])
@authenticate
def get_workouts_by_sport(
auth_user_id: int, user_name: str
auth_user: User, user_name: str
) -> Union[Dict, HttpResponse]:
"""
Get workouts statistics for a user by sport
@ -361,7 +360,6 @@ def get_workouts_by_sport(
"status": "success"
}
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:param integer user_name: user name
:query integer sport_id: sport id
@ -383,7 +381,7 @@ def get_workouts_by_sport(
@stats_blueprint.route('/stats/all', methods=['GET'])
@authenticate_as_admin
def get_application_stats(auth_user_id: int) -> Dict:
def get_application_stats(auth_user: User) -> Dict:
"""
Get all application statistics
@ -411,8 +409,6 @@ def get_application_stats(auth_user_id: int) -> Dict:
"status": "success"
}
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:reqheader Authorization: OAuth 2.0 Bearer Token
:statuscode 200: success

View File

@ -186,7 +186,7 @@ def update_workout(workout: Workout) -> Workout:
def edit_workout(
workout: Workout, workout_data: Dict, auth_user_id: int
workout: Workout, workout_data: Dict, auth_user: User
) -> Workout:
"""
Edit an workout
@ -195,7 +195,6 @@ def edit_workout(
In a next version, map_data and weather_data will be updated
(case of a modified gpx file, see issue #7)
"""
user = User.query.filter_by(id=auth_user_id).first()
if workout_data.get('refresh'):
workout = update_workout(workout)
if workout_data.get('sport_id'):
@ -210,7 +209,7 @@ def edit_workout(
workout_data['workout_date'], '%Y-%m-%d %H:%M'
)
_, workout.workout_date = get_datetime_with_tz(
user.timezone, workout_date
auth_user.timezone, workout_date
)
if workout_data.get('duration'):
@ -299,9 +298,9 @@ def process_one_gpx_file(
gpx_data, map_data, weather_data = get_gpx_info(
params['file_path'], stopped_speed_threshold
)
auth_user_id = params['user'].id
auth_user = params['auth_user']
new_filepath = get_new_file_path(
auth_user_id=auth_user_id,
auth_user_id=auth_user.id,
workout_date=gpx_data['start'],
old_filename=filename,
sport=params['sport_label'],
@ -311,7 +310,7 @@ def process_one_gpx_file(
gpx_data['filename'] = new_filepath
map_filepath = get_new_file_path(
auth_user_id=auth_user_id,
auth_user_id=auth_user.id,
workout_date=gpx_data['start'],
extension='.png',
sport=params['sport_label'],
@ -325,7 +324,7 @@ def process_one_gpx_file(
try:
new_workout = create_workout(
params['user'], params['workout_data'], gpx_data
auth_user, params['workout_data'], gpx_data
)
new_workout.map = map_filepath
new_workout.map_id = get_map_hash(map_filepath)
@ -380,7 +379,7 @@ def process_zip_archive(
def process_files(
auth_user_id: int,
auth_user: User,
workout_data: Dict,
workout_file: FileStorage,
folders: Dict,
@ -399,9 +398,8 @@ def process_files(
'error',
f"Sport id: {workout_data.get('sport_id')} does not exist",
)
user = User.query.filter_by(id=auth_user_id).first()
sport_preferences = UserSportPreference.query.filter_by(
user_id=user.id, sport_id=sport.id
user_id=auth_user.id, sport_id=sport.id
).first()
stopped_speed_threshold = (
sport.stopped_speed_threshold
@ -410,7 +408,7 @@ def process_files(
)
common_params = {
'user': user,
'auth_user': auth_user,
'workout_data': workout_data,
'file_path': file_path,
'sport_label': sport.label,

View File

@ -56,7 +56,7 @@ MAX_WORKOUTS_PER_PAGE = 100
@workouts_blueprint.route('/workouts', methods=['GET'])
@authenticate
def get_workouts(auth_user_id: int) -> Union[Dict, HttpResponse]:
def get_workouts(auth_user: User) -> Union[Dict, HttpResponse]:
"""
Get workouts for the authenticated user.
@ -171,8 +171,6 @@ def get_workouts(auth_user_id: int) -> Union[Dict, HttpResponse]:
"status": "success"
}
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:query integer page: page if using pagination (default: 1)
:query integer per_page: number of workouts per page
(default: 5, max: 100)
@ -200,10 +198,9 @@ def get_workouts(auth_user_id: int) -> Union[Dict, HttpResponse]:
"""
try:
user = User.query.filter_by(id=auth_user_id).first()
params = request.args.copy()
page = int(params.get('page', 1))
date_from, date_to = get_datetime_from_request_args(params, user)
date_from, date_to = get_datetime_from_request_args(params, auth_user)
distance_from = params.get('distance_from')
distance_to = params.get('distance_to')
duration_from = params.get('duration_from')
@ -220,7 +217,7 @@ def get_workouts(auth_user_id: int) -> Union[Dict, HttpResponse]:
per_page = MAX_WORKOUTS_PER_PAGE
workouts_pagination = (
Workout.query.filter(
Workout.user_id == auth_user_id,
Workout.user_id == auth_user.id,
Workout.sport_id == sport_id if sport_id else True,
Workout.workout_date >= date_from if date_from else True,
Workout.workout_date < date_to + timedelta(seconds=1)
@ -302,7 +299,7 @@ def get_workouts(auth_user_id: int) -> Union[Dict, HttpResponse]:
)
@authenticate
def get_workout(
auth_user_id: int, workout_short_id: str
auth_user: User, workout_short_id: str
) -> Union[Dict, HttpResponse]:
"""
Get an workout
@ -373,7 +370,6 @@ def get_workout(
"status": "not found"
}
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:param string workout_short_id: workout short id
:reqheader Authorization: OAuth 2.0 Bearer Token
@ -392,7 +388,7 @@ def get_workout(
if not workout:
return DataNotFoundErrorResponse('workouts')
error_response = can_view_workout(auth_user_id, workout.user_id)
error_response = can_view_workout(auth_user.id, workout.user_id)
if error_response:
return error_response
@ -403,7 +399,7 @@ def get_workout(
def get_workout_data(
auth_user_id: int,
auth_user: User,
workout_short_id: str,
data_type: str,
segment_id: Optional[int] = None,
@ -417,7 +413,7 @@ def get_workout_data(
message=f'workout not found (id: {workout_short_id})',
)
error_response = can_view_workout(auth_user_id, workout.user_id)
error_response = can_view_workout(auth_user.id, workout.user_id)
if error_response:
return error_response
if not workout.gpx or workout.gpx == '':
@ -467,7 +463,7 @@ def get_workout_data(
)
@authenticate
def get_workout_gpx(
auth_user_id: int, workout_short_id: str
auth_user: User, workout_short_id: str
) -> Union[Dict, HttpResponse]:
"""
Get gpx file for an workout displayed on map with Leaflet
@ -494,7 +490,6 @@ def get_workout_gpx(
"status": "success"
}
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:param string workout_short_id: workout short id
:reqheader Authorization: OAuth 2.0 Bearer Token
@ -510,7 +505,7 @@ def get_workout_gpx(
:statuscode 500:
"""
return get_workout_data(auth_user_id, workout_short_id, 'gpx')
return get_workout_data(auth_user, workout_short_id, 'gpx')
@workouts_blueprint.route(
@ -518,7 +513,7 @@ def get_workout_gpx(
)
@authenticate
def get_workout_chart_data(
auth_user_id: int, workout_short_id: str
auth_user: User, workout_short_id: str
) -> Union[Dict, HttpResponse]:
"""
Get chart data from an workout gpx file, to display it with Recharts
@ -564,7 +559,6 @@ def get_workout_chart_data(
"status": "success"
}
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:param string workout_short_id: workout short id
:reqheader Authorization: OAuth 2.0 Bearer Token
@ -580,7 +574,7 @@ def get_workout_chart_data(
:statuscode 500:
"""
return get_workout_data(auth_user_id, workout_short_id, 'chart_data')
return get_workout_data(auth_user, workout_short_id, 'chart_data')
@workouts_blueprint.route(
@ -589,7 +583,7 @@ def get_workout_chart_data(
)
@authenticate
def get_segment_gpx(
auth_user_id: int, workout_short_id: str, segment_id: int
auth_user: User, workout_short_id: str, segment_id: int
) -> Union[Dict, HttpResponse]:
"""
Get gpx file for an workout segment displayed on map with Leaflet
@ -616,7 +610,6 @@ def get_segment_gpx(
"status": "success"
}
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:param string workout_short_id: workout short id
:param integer segment_id: segment id
@ -632,7 +625,7 @@ def get_segment_gpx(
:statuscode 500:
"""
return get_workout_data(auth_user_id, workout_short_id, 'gpx', segment_id)
return get_workout_data(auth_user, workout_short_id, 'gpx', segment_id)
@workouts_blueprint.route(
@ -642,7 +635,7 @@ def get_segment_gpx(
)
@authenticate
def get_segment_chart_data(
auth_user_id: int, workout_short_id: str, segment_id: int
auth_user: User, workout_short_id: str, segment_id: int
) -> Union[Dict, HttpResponse]:
"""
Get chart data from an workout gpx file, to display it with Recharts
@ -688,7 +681,6 @@ def get_segment_chart_data(
"status": "success"
}
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:param string workout_short_id: workout short id
:param integer segment_id: segment id
@ -705,7 +697,7 @@ def get_segment_chart_data(
"""
return get_workout_data(
auth_user_id, workout_short_id, 'chart_data', segment_id
auth_user, workout_short_id, 'chart_data', segment_id
)
@ -714,7 +706,7 @@ def get_segment_chart_data(
)
@authenticate
def download_workout_gpx(
auth_user_id: int, workout_short_id: str
auth_user: User, workout_short_id: str
) -> Union[HttpResponse, Response]:
"""
Download gpx file
@ -732,7 +724,6 @@ def download_workout_gpx(
HTTP/1.1 200 OK
Content-Type: application/gpx+xml
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:param string workout_short_id: workout short id
:statuscode 200: success
@ -746,7 +737,7 @@ def download_workout_gpx(
"""
workout_uuid = decode_short_id(workout_short_id)
workout = Workout.query.filter_by(
uuid=workout_uuid, user_id=auth_user_id
uuid=workout_uuid, user_id=auth_user.id
).first()
if not workout:
return DataNotFoundErrorResponse(
@ -852,7 +843,7 @@ def get_map_tile(s: str, z: str, x: str, y: str) -> Tuple[Response, int]:
@workouts_blueprint.route('/workouts', methods=['POST'])
@authenticate
def post_workout(auth_user_id: int) -> Union[Tuple[Dict, int], HttpResponse]:
def post_workout(auth_user: User) -> Union[Tuple[Dict, int], HttpResponse]:
"""
Post an workout with a gpx file
@ -944,8 +935,6 @@ def post_workout(auth_user_id: int) -> Union[Tuple[Dict, int], HttpResponse]:
"status": "success"
}
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:form file: gpx file (allowed extensions: .gpx, .zip)
:form data: sport id and notes (example: ``{"sport_id": 1, "notes": ""}``)
@ -983,7 +972,7 @@ def post_workout(auth_user_id: int) -> Union[Tuple[Dict, int], HttpResponse]:
workout_file = request.files['file']
upload_dir = os.path.join(
current_app.config['UPLOAD_FOLDER'], 'workouts', str(auth_user_id)
current_app.config['UPLOAD_FOLDER'], 'workouts', str(auth_user.id)
)
folders = {
'extract_dir': os.path.join(upload_dir, 'extract'),
@ -992,7 +981,7 @@ def post_workout(auth_user_id: int) -> Union[Tuple[Dict, int], HttpResponse]:
try:
new_workouts = process_files(
auth_user_id, workout_data, workout_file, folders
auth_user, workout_data, workout_file, folders
)
if len(new_workouts) > 0:
response_object = {
@ -1021,7 +1010,7 @@ def post_workout(auth_user_id: int) -> Union[Tuple[Dict, int], HttpResponse]:
@workouts_blueprint.route('/workouts/no_gpx', methods=['POST'])
@authenticate
def post_workout_no_gpx(
auth_user_id: int,
auth_user: User,
) -> Union[Tuple[Dict, int], HttpResponse]:
"""
Post an workout without gpx file
@ -1114,8 +1103,6 @@ def post_workout_no_gpx(
"status": "success"
}
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:<json string workout_date: workout date (format: ``%Y-%m-%d %H:%M``)
:<json float distance: workout distance in km
:<json integer duration: workout duration in seconds
@ -1145,8 +1132,7 @@ def post_workout_no_gpx(
return InvalidPayloadErrorResponse()
try:
user = User.query.filter_by(id=auth_user_id).first()
new_workout = create_workout(user, workout_data)
new_workout = create_workout(auth_user, workout_data)
db.session.add(new_workout)
db.session.commit()
@ -1172,7 +1158,7 @@ def post_workout_no_gpx(
)
@authenticate
def update_workout(
auth_user_id: int, workout_short_id: str
auth_user: User, workout_short_id: str
) -> Union[Dict, HttpResponse]:
"""
Update an workout
@ -1265,7 +1251,6 @@ def update_workout(
"status": "success"
}
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:param string workout_short_id: workout short id
:<json string workout_date: workout date (format: ``%Y-%m-%d %H:%M``)
@ -1300,11 +1285,11 @@ def update_workout(
if not workout:
return DataNotFoundErrorResponse('workouts')
response_object = can_view_workout(auth_user_id, workout.user_id)
response_object = can_view_workout(auth_user.id, workout.user_id)
if response_object:
return response_object
workout = edit_workout(workout, workout_data, auth_user_id)
workout = edit_workout(workout, workout_data, auth_user)
db.session.commit()
return {
'status': 'success',
@ -1320,7 +1305,7 @@ def update_workout(
)
@authenticate
def delete_workout(
auth_user_id: int, workout_short_id: str
auth_user: User, workout_short_id: str
) -> Union[Tuple[Dict, int], HttpResponse]:
"""
Delete an workout
@ -1339,7 +1324,6 @@ def delete_workout(
HTTP/1.1 204 NO CONTENT
Content-Type: application/json
:param integer auth_user_id: authenticate user id (from JSON Web Token)
:param string workout_short_id: workout short id
:reqheader Authorization: OAuth 2.0 Bearer Token
@ -1359,7 +1343,7 @@ def delete_workout(
workout = Workout.query.filter_by(uuid=workout_uuid).first()
if not workout:
return DataNotFoundErrorResponse('workouts')
error_response = can_view_workout(auth_user_id, workout.user_id)
error_response = can_view_workout(auth_user.id, workout.user_id)
if error_response:
return error_response

View File

@ -1,6 +1,6 @@
{
"name": "fittrackee_client",
"version": "0.5.1",
"version": "0.5.2",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",

View File

@ -0,0 +1,62 @@
<template>
<svg
version="1.1"
id="Capa_1"
x="0px"
y="0px"
viewBox="0 0 494.49 494.49"
style="enable-background: new 0 0 494.49 494.49"
xml:space="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
>
<desc id="snowshoesDescription">silhouette of a person with snowshoes</desc>
<a id="a941">
<g id="g6">
<path
d="M282.74,80.771c22.318,0,40.401-18.08,40.401-40.389C323.141,18.084,305.058,0,282.74,0 c-22.281,0-40.378,18.084-40.378,40.383C242.362,62.691,260.458,80.771,282.74,80.771z"
id="path2"
/>
<path
d="M 400.207,188.547 H 331.47 l -38.766,-55.03 0.123,-0.944 c 1.384,-10.514 -1.475,-21.146 -7.94,-29.556 -6.461,-8.409 -16.007,-13.903 -26.52,-15.287 -10.926,-1.429 -22.619,3.12 -31.206,8.646 -1.441,0.928 -84.97,54.921 -84.97,54.921 -5.175,3.358 -8.542,8.877 -9.165,15.016 -0.634,6.13 1.574,12.222 5.976,16.541 l 58.982,58 -6.417,48.954 -18.707,65.584 -65.05119,31.97053 c -12.988666,4.46731 -20.184548,18.48046 -15.989971,31.3127 4.211472,12.82063 18.196961,19.59882 31.244871,15.13083 L 197.478,400.879 c 5.655,-3.146 9.833,-8.409 11.611,-14.635 l 25.963,-71.057 26.365,36.639 6.684,83.628 c 0.73,12.991 11.501,23.036 24.349,23.036 0.441,0 0.92,-0.016 1.379,-0.039 13.453,-0.748 23.745,-12.262 23,-25.713 l -7.083,-90.736 c -0.271,-4.643 -1.846,-9.116 -4.56,-12.887 l -32.24,-44.811 11.959,-91.279 19.409,27.555 c 3.794,5.407 10.005,8.624 16.613,8.624 h 79.28 c 11.226,0 20.326,-9.101 20.326,-20.329 0,-11.228 -9.101,-20.328 -20.326,-20.328 z m -195.601,1.81 -19.026,-18.717 23.476,-15.206 z"
id="path4"
/>
</g>
</a>
<path
d="m 298.71755,466.89876 c 34.77016,0 59.21435,1.29141 59.21435,-13.23956 0,-14.53096 4.12606,-16.02074 -29.36635,-12.11757 -30.73634,3.582 -85.42111,4.42691 -90.30047,14.96259 -4.90812,10.59778 25.68237,10.39454 60.45247,10.39454 z"
id="path4-3"
style="stroke-width: 3.76193"
/>
<path
d="m 87.671049,426.72238 c 15.942661,30.89977 26.003031,53.21513 38.916511,46.55245 12.91346,-6.66266 16.12928,-3.67899 -2.6962,-31.65357 C 106.615,415.9487 80.790319,367.73849 69.190141,368.23304 c -11.668553,0.49747 2.538273,27.58962 18.480908,58.48934 z"
id="path4-3-3"
style="stroke-width: 3.76193"
/>
<rect
style="stroke-width: 0.701998"
id="rect1062"
width="9.7789898"
height="242.75766"
x="397.1806"
y="203.58122"
ry="4.8894949"
/>
<rect
style="stroke-width: 0.701998"
id="rect1062-7"
width="9.7789898"
height="242.75766"
x="296.39819"
y="-78.536827"
ry="4.8894949"
transform="rotate(54.243176)"
/>
</svg>
</template>
<script>
export default {
name: 'Snowshoes',
}
</script>

View File

@ -15,6 +15,7 @@
<Running v-if="sportLabel === 'Running'" />
<SkiingAlpine v-if="sportLabel === 'Skiing (Alpine)'" />
<SkiingCrossCountry v-if="sportLabel === 'Skiing (Cross Country)'" />
<Snowshoes v-if="sportLabel === 'Snowshoes'" />
<Trail v-if="sportLabel === 'Trail'" />
<Walking v-if="sportLabel === 'Walking'" />
</div>
@ -32,6 +33,7 @@
import Running from '@/components/Common/Images/SportImage/Running.vue'
import SkiingAlpine from '@/components/Common/Images/SportImage/SkiingAlpine.vue'
import SkiingCrossCountry from '@/components/Common/Images/SportImage/SkiingCrossCountry.vue'
import Snowshoes from '@/components/Common/Images/SportImage/Snowshoes.vue'
import Trail from '@/components/Common/Images/SportImage/Trail.vue'
import Walking from '@/components/Common/Images/SportImage/Walking.vue'

View File

@ -135,6 +135,12 @@
<button :disabled="loading" @click="updateSport">
{{ $t('buttons.SUBMIT') }}
</button>
<button
:disabled="loading"
@click="(e) => resetSport(e, sport.id)"
>
{{ $t('buttons.RESET') }}
</button>
<button :disabled="loading" @click="updateSportInEdition(null)">
{{ $t('buttons.CANCEL') }}
</button>
@ -234,6 +240,13 @@
sportPayload
)
}
function resetSport(event: Event, sportId: number) {
event.preventDefault()
store.dispatch(
AUTH_USER_STORE.ACTIONS.RESET_USER_SPORT_PREFERENCES,
sportId
)
}
watch(
() => loading.value,

View File

@ -10,6 +10,7 @@
"LOGIN": "Log in",
"NO": "No",
"REGISTER": "Register",
"RESET": "Reset",
"SUBMIT": "Submit",
"YES": "Yes"
}

View File

@ -26,6 +26,9 @@
"Skiing (Cross Country)": {
"LABEL": "Skiing (Cross Country)"
},
"Snowshoes": {
"LABEL": "Snowshoes"
},
"Trail": {
"LABEL": "Trail"
},

View File

@ -10,6 +10,7 @@
"LOGIN": "Se connecter",
"NO": "Non",
"REGISTER": "S'inscrire",
"RESET": "Réinit.",
"SUBMIT": "Valider",
"YES": "Oui"
}

View File

@ -26,6 +26,9 @@
"Skiing (Cross Country)": {
"LABEL": "Ski (Randonnée)"
},
"Snowshoes": {
"LABEL": "Raquettes"
},
"Trail": {
"LABEL": "Trail"
},

View File

@ -174,6 +174,26 @@ export const actions: ActionTree<IAuthUserState, IRootState> &
context.commit(AUTH_USER_STORE.MUTATIONS.UPDATE_USER_LOADING, false)
)
},
[AUTH_USER_STORE.ACTIONS.RESET_USER_SPORT_PREFERENCES](
context: ActionContext<IAuthUserState, IRootState>,
sportId: number
): void {
context.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES)
context.commit(AUTH_USER_STORE.MUTATIONS.UPDATE_USER_LOADING, true)
authApi
.delete(`auth/profile/reset/sports/${sportId}`)
.then((res) => {
if (res.status === 204) {
context.dispatch(SPORTS_STORE.ACTIONS.GET_SPORTS)
} else {
handleError(context, null)
}
})
.catch((error) => {
handleError(context, error)
context.commit(AUTH_USER_STORE.MUTATIONS.UPDATE_USER_LOADING, false)
})
},
[AUTH_USER_STORE.ACTIONS.UPDATE_USER_SPORT_PREFERENCES](
context: ActionContext<IAuthUserState, IRootState>,
payload: IUserSportPreferencesPayload

View File

@ -7,6 +7,7 @@ export enum AuthUserActions {
LOGOUT = 'LOGOUT',
SEND_PASSWORD_RESET_REQUEST = 'SEND_PASSWORD_RESET_REQUEST',
RESET_USER_PASSWORD = 'RESET_USER_PASSWORD',
RESET_USER_SPORT_PREFERENCES = 'RESET_USER_SPORT_PREFERENCES',
UPDATE_USER_PICTURE = 'UPDATE_USER_PICTURE',
UPDATE_USER_PROFILE = 'UPDATE_USER_PROFILE',
UPDATE_USER_PREFERENCES = 'UPDATE_USER_PREFERENCES',

View File

@ -73,6 +73,11 @@ export interface IAuthUserActions {
payload: IUserPasswordResetPayload
): void
[AUTH_USER_STORE.ACTIONS.RESET_USER_SPORT_PREFERENCES](
context: ActionContext<IAuthUserState, IRootState>,
sportId: number
): void
[AUTH_USER_STORE.ACTIONS.DELETE_ACCOUNT](
context: ActionContext<IAuthUserState, IRootState>,
payload: IUserDeletionPayload

View File

@ -12,6 +12,7 @@ export const sportColors: Record<string, string> = {
Running: '#835b83',
'Skiing (Alpine)': '#67a4bd',
'Skiing (Cross Country)': '#9498d0',
Snowshoes: '#5780a8',
Trail: '#09a98a',
Walking: '#838383',
}

File diff suppressed because it is too large Load Diff

326
poetry.lock generated
View File

@ -82,7 +82,7 @@ typecheck = ["mypy"]
[[package]]
name = "black"
version = "21.11b1"
version = "21.12b0"
description = "The uncompromising code formatter."
category = "dev"
optional = false
@ -93,7 +93,6 @@ click = ">=7.1.2"
mypy-extensions = ">=0.4.3"
pathspec = ">=0.9.0,<1"
platformdirs = ">=2"
regex = ">=2021.4.4"
tomli = ">=0.2.6,<2.0.0"
typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""}
typing-extensions = [
@ -129,7 +128,7 @@ pycparser = "*"
[[package]]
name = "charset-normalizer"
version = "2.0.8"
version = "2.0.9"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
category = "main"
optional = false
@ -185,7 +184,7 @@ toml = ["tomli"]
[[package]]
name = "cryptography"
version = "36.0.0"
version = "36.0.1"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
category = "dev"
optional = false
@ -365,7 +364,7 @@ python-versions = ">=3.6"
[[package]]
name = "humanize"
version = "3.12.0"
version = "3.13.1"
description = "Python humanize utilities"
category = "main"
optional = false
@ -501,21 +500,21 @@ python-versions = "*"
[[package]]
name = "mypy"
version = "0.910"
version = "0.920"
description = "Optional static typing for Python"
category = "dev"
optional = false
python-versions = ">=3.5"
python-versions = ">=3.6"
[package.dependencies]
mypy-extensions = ">=0.4.3,<0.5.0"
toml = "*"
typed-ast = {version = ">=1.4.0,<1.5.0", markers = "python_version < \"3.8\""}
tomli = ">=1.1.0,<3.0.0"
typed-ast = {version = ">=1.4.0,<2", markers = "python_version < \"3.8\""}
typing-extensions = ">=3.7.4"
[package.extras]
dmypy = ["psutil (>=4.0)"]
python2 = ["typed-ast (>=1.4.0,<1.5.0)"]
python2 = ["typed-ast (>=1.4.0,<2)"]
[[package]]
name = "mypy-extensions"
@ -904,14 +903,6 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[package.extras]
hiredis = ["hiredis (>=0.1.3)"]
[[package]]
name = "regex"
version = "2021.11.10"
description = "Alternative regular expression module, to replace re."
category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "requests"
version = "2.26.0"
@ -1123,7 +1114,7 @@ test = ["pytest"]
[[package]]
name = "sqlalchemy"
version = "1.4.27"
version = "1.4.28"
description = "Database Abstraction Library"
category = "main"
optional = false
@ -1190,7 +1181,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
name = "tomli"
version = "1.2.2"
version = "1.2.3"
description = "A lil' TOML parser"
category = "dev"
optional = false
@ -1244,11 +1235,11 @@ wsproto = ">=0.14"
[[package]]
name = "typed-ast"
version = "1.4.3"
version = "1.5.1"
description = "a fork of Python 2 and 3 ast modules with type comment support"
category = "dev"
optional = false
python-versions = "*"
python-versions = ">=3.6"
[[package]]
name = "types-freezegun"
@ -1260,7 +1251,7 @@ python-versions = "*"
[[package]]
name = "types-pytz"
version = "2021.3.1"
version = "2021.3.3"
description = "Typing stubs for pytz"
category = "dev"
optional = false
@ -1268,7 +1259,7 @@ python-versions = "*"
[[package]]
name = "types-requests"
version = "2.26.1"
version = "2.26.2"
description = "Typing stubs for requests"
category = "dev"
optional = false
@ -1276,7 +1267,7 @@ python-versions = "*"
[[package]]
name = "typing-extensions"
version = "4.0.0"
version = "4.0.1"
description = "Backported and Experimental Type Hints for Python 3.6+"
category = "main"
optional = false
@ -1338,7 +1329,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytes
[metadata]
lock-version = "1.1"
python-versions = "^3.7"
content-hash = "a4b9ea8f913bee94bcd144aa918e7c29065a516eb280c46c89787af1de168039"
content-hash = "930b7b9d75a0f79ef16aef368568b11e1bc4b3f6fb09a1c5a93dc2b52fe589a5"
[metadata.files]
alabaster = [
@ -1375,8 +1366,8 @@ bcrypt = [
{file = "bcrypt-3.2.0.tar.gz", hash = "sha256:5b93c1726e50a93a033c36e5ca7fdcd29a5c7395af50a6892f5d9e7c6cfbfb29"},
]
black = [
{file = "black-21.11b1-py3-none-any.whl", hash = "sha256:802c6c30b637b28645b7fde282ed2569c0cd777dbe493a41b6a03c1d903f99ac"},
{file = "black-21.11b1.tar.gz", hash = "sha256:a042adbb18b3262faad5aff4e834ff186bb893f95ba3a8013f09de1e5569def2"},
{file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"},
{file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"},
]
certifi = [
{file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"},
@ -1435,8 +1426,8 @@ cffi = [
{file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"},
]
charset-normalizer = [
{file = "charset-normalizer-2.0.8.tar.gz", hash = "sha256:735e240d9a8506778cd7a453d97e817e536bb1fc29f4f6961ce297b9c7a917b0"},
{file = "charset_normalizer-2.0.8-py3-none-any.whl", hash = "sha256:83fcdeb225499d6344c8f7f34684c2981270beacc32ede2e669e94f7fa544405"},
{file = "charset-normalizer-2.0.9.tar.gz", hash = "sha256:b0b883e8e874edfdece9c28f314e3dd5badf067342e42fb162203335ae61aa2c"},
{file = "charset_normalizer-2.0.9-py3-none-any.whl", hash = "sha256:1eecaa09422db5be9e29d7fc65664e6c33bd06f9ced7838578ba40d58bdf3721"},
]
click = [
{file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"},
@ -1500,27 +1491,26 @@ coverage = [
{file = "coverage-6.2.tar.gz", hash = "sha256:e2cad8093172b7d1595b4ad66f24270808658e11acf43a8f95b41276162eb5b8"},
]
cryptography = [
{file = "cryptography-36.0.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:9511416e85e449fe1de73f7f99b21b3aa04fba4c4d335d30c486ba3756e3a2a6"},
{file = "cryptography-36.0.0-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:97199a13b772e74cdcdb03760c32109c808aff7cd49c29e9cf4b7754bb725d1d"},
{file = "cryptography-36.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:494106e9cd945c2cadfce5374fa44c94cfadf01d4566a3b13bb487d2e6c7959e"},
{file = "cryptography-36.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6fbbbb8aab4053fa018984bb0e95a16faeb051dd8cca15add2a27e267ba02b58"},
{file = "cryptography-36.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:684993ff6f67000a56454b41bdc7e015429732d65a52d06385b6e9de6181c71e"},
{file = "cryptography-36.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c702855cd3174666ef0d2d13dcc879090aa9c6c38f5578896407a7028f75b9f"},
{file = "cryptography-36.0.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d91bc9f535599bed58f6d2e21a2724cb0c3895bf41c6403fe881391d29096f1d"},
{file = "cryptography-36.0.0-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:b17d83b3d1610e571fedac21b2eb36b816654d6f7496004d6a0d32f99d1d8120"},
{file = "cryptography-36.0.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:8982c19bb90a4fa2aad3d635c6d71814e38b643649b4000a8419f8691f20ac44"},
{file = "cryptography-36.0.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:24469d9d33217ffd0ce4582dfcf2a76671af115663a95328f63c99ec7ece61a4"},
{file = "cryptography-36.0.0-cp36-abi3-win32.whl", hash = "sha256:f6a5a85beb33e57998dc605b9dbe7deaa806385fdf5c4810fb849fcd04640c81"},
{file = "cryptography-36.0.0-cp36-abi3-win_amd64.whl", hash = "sha256:2deab5ec05d83ddcf9b0916319674d3dae88b0e7ee18f8962642d3cde0496568"},
{file = "cryptography-36.0.0-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2049f8b87f449fc6190350de443ee0c1dd631f2ce4fa99efad2984de81031681"},
{file = "cryptography-36.0.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a776bae1629c8d7198396fd93ec0265f8dd2341c553dc32b976168aaf0e6a636"},
{file = "cryptography-36.0.0-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:aa94d617a4cd4cdf4af9b5af65100c036bce22280ebb15d8b5262e8273ebc6ba"},
{file = "cryptography-36.0.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:5c49c9e8fb26a567a2b3fa0343c89f5d325447956cc2fc7231c943b29a973712"},
{file = "cryptography-36.0.0-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ef216d13ac8d24d9cd851776662f75f8d29c9f2d05cdcc2d34a18d32463a9b0b"},
{file = "cryptography-36.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:231c4a69b11f6af79c1495a0e5a85909686ea8db946935224b7825cfb53827ed"},
{file = "cryptography-36.0.0-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:f92556f94e476c1b616e6daec5f7ddded2c082efa7cee7f31c7aeda615906ed8"},
{file = "cryptography-36.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d73e3a96c38173e0aa5646c31bf8473bc3564837977dd480f5cbeacf1d7ef3a3"},
{file = "cryptography-36.0.0.tar.gz", hash = "sha256:52f769ecb4ef39865719aedc67b4b7eae167bafa48dbc2a26dd36fa56460507f"},
{file = "cryptography-36.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:73bc2d3f2444bcfeac67dd130ff2ea598ea5f20b40e36d19821b4df8c9c5037b"},
{file = "cryptography-36.0.1-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:2d87cdcb378d3cfed944dac30596da1968f88fb96d7fc34fdae30a99054b2e31"},
{file = "cryptography-36.0.1-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74d6c7e80609c0f4c2434b97b80c7f8fdfaa072ca4baab7e239a15d6d70ed73a"},
{file = "cryptography-36.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:6c0c021f35b421ebf5976abf2daacc47e235f8b6082d3396a2fe3ccd537ab173"},
{file = "cryptography-36.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d59a9d55027a8b88fd9fd2826c4392bd487d74bf628bb9d39beecc62a644c12"},
{file = "cryptography-36.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a817b961b46894c5ca8a66b599c745b9a3d9f822725221f0e0fe49dc043a3a3"},
{file = "cryptography-36.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:94ae132f0e40fe48f310bba63f477f14a43116f05ddb69d6fa31e93f05848ae2"},
{file = "cryptography-36.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7be0eec337359c155df191d6ae00a5e8bbb63933883f4f5dffc439dac5348c3f"},
{file = "cryptography-36.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:e0344c14c9cb89e76eb6a060e67980c9e35b3f36691e15e1b7a9e58a0a6c6dc3"},
{file = "cryptography-36.0.1-cp36-abi3-win32.whl", hash = "sha256:4caa4b893d8fad33cf1964d3e51842cd78ba87401ab1d2e44556826df849a8ca"},
{file = "cryptography-36.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:391432971a66cfaf94b21c24ab465a4cc3e8bf4a939c1ca5c3e3a6e0abebdbcf"},
{file = "cryptography-36.0.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bb5829d027ff82aa872d76158919045a7c1e91fbf241aec32cb07956e9ebd3c9"},
{file = "cryptography-36.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebc15b1c22e55c4d5566e3ca4db8689470a0ca2babef8e3a9ee057a8b82ce4b1"},
{file = "cryptography-36.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:596f3cd67e1b950bc372c33f1a28a0692080625592ea6392987dba7f09f17a94"},
{file = "cryptography-36.0.1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:30ee1eb3ebe1644d1c3f183d115a8c04e4e603ed6ce8e394ed39eea4a98469ac"},
{file = "cryptography-36.0.1-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec63da4e7e4a5f924b90af42eddf20b698a70e58d86a72d943857c4c6045b3ee"},
{file = "cryptography-36.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca238ceb7ba0bdf6ce88c1b74a87bffcee5afbfa1e41e173b1ceb095b39add46"},
{file = "cryptography-36.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:ca28641954f767f9822c24e927ad894d45d5a1e501767599647259cbf030b903"},
{file = "cryptography-36.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:39bdf8e70eee6b1c7b289ec6e5d84d49a6bfa11f8b8646b5b3dfe41219153316"},
{file = "cryptography-36.0.1.tar.gz", hash = "sha256:53e5c1dc3d7a953de055d77bef2ff607ceef7a2aac0353b5d630ab67f7423638"},
]
docutils = [
{file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"},
@ -1620,8 +1610,8 @@ h11 = [
{file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"},
]
humanize = [
{file = "humanize-3.12.0-py3-none-any.whl", hash = "sha256:4c71c4381f0209715cd993058e717c1b74d58ae2f8c6da7bdb59ab66473b9ab0"},
{file = "humanize-3.12.0.tar.gz", hash = "sha256:5ec1a66e230a3e31fb3f184aab9436ea13d4e37c168e0ffc345ae5bb57e58be6"},
{file = "humanize-3.13.1-py3-none-any.whl", hash = "sha256:a6f7cc1597db69a4e571ad5e19b4da07ee871da5a9de2b233dbfab02d98e9754"},
{file = "humanize-3.13.1.tar.gz", hash = "sha256:12f113f2e369dac7f35d3823f49262934f4a22a53a6d3d4c86b736f50db88c7b"},
]
idna = [
{file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
@ -1700,29 +1690,26 @@ mccabe = [
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
]
mypy = [
{file = "mypy-0.910-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:a155d80ea6cee511a3694b108c4494a39f42de11ee4e61e72bc424c490e46457"},
{file = "mypy-0.910-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b94e4b785e304a04ea0828759172a15add27088520dc7e49ceade7834275bedb"},
{file = "mypy-0.910-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:088cd9c7904b4ad80bec811053272986611b84221835e079be5bcad029e79dd9"},
{file = "mypy-0.910-cp35-cp35m-win_amd64.whl", hash = "sha256:adaeee09bfde366d2c13fe6093a7df5df83c9a2ba98638c7d76b010694db760e"},
{file = "mypy-0.910-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ecd2c3fe726758037234c93df7e98deb257fd15c24c9180dacf1ef829da5f921"},
{file = "mypy-0.910-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d9dd839eb0dc1bbe866a288ba3c1afc33a202015d2ad83b31e875b5905a079b6"},
{file = "mypy-0.910-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:3e382b29f8e0ccf19a2df2b29a167591245df90c0b5a2542249873b5c1d78212"},
{file = "mypy-0.910-cp36-cp36m-win_amd64.whl", hash = "sha256:53fd2eb27a8ee2892614370896956af2ff61254c275aaee4c230ae771cadd885"},
{file = "mypy-0.910-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b6fb13123aeef4a3abbcfd7e71773ff3ff1526a7d3dc538f3929a49b42be03f0"},
{file = "mypy-0.910-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e4dab234478e3bd3ce83bac4193b2ecd9cf94e720ddd95ce69840273bf44f6de"},
{file = "mypy-0.910-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:7df1ead20c81371ccd6091fa3e2878559b5c4d4caadaf1a484cf88d93ca06703"},
{file = "mypy-0.910-cp37-cp37m-win_amd64.whl", hash = "sha256:0aadfb2d3935988ec3815952e44058a3100499f5be5b28c34ac9d79f002a4a9a"},
{file = "mypy-0.910-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ec4e0cd079db280b6bdabdc807047ff3e199f334050db5cbb91ba3e959a67504"},
{file = "mypy-0.910-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:119bed3832d961f3a880787bf621634ba042cb8dc850a7429f643508eeac97b9"},
{file = "mypy-0.910-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:866c41f28cee548475f146aa4d39a51cf3b6a84246969f3759cb3e9c742fc072"},
{file = "mypy-0.910-cp38-cp38-win_amd64.whl", hash = "sha256:ceb6e0a6e27fb364fb3853389607cf7eb3a126ad335790fa1e14ed02fba50811"},
{file = "mypy-0.910-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a85e280d4d217150ce8cb1a6dddffd14e753a4e0c3cf90baabb32cefa41b59e"},
{file = "mypy-0.910-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:42c266ced41b65ed40a282c575705325fa7991af370036d3f134518336636f5b"},
{file = "mypy-0.910-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:3c4b8ca36877fc75339253721f69603a9c7fdb5d4d5a95a1a1b899d8b86a4de2"},
{file = "mypy-0.910-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:c0df2d30ed496a08de5daed2a9ea807d07c21ae0ab23acf541ab88c24b26ab97"},
{file = "mypy-0.910-cp39-cp39-win_amd64.whl", hash = "sha256:c6c2602dffb74867498f86e6129fd52a2770c48b7cd3ece77ada4fa38f94eba8"},
{file = "mypy-0.910-py3-none-any.whl", hash = "sha256:ef565033fa5a958e62796867b1df10c40263ea9ded87164d67572834e57a174d"},
{file = "mypy-0.910.tar.gz", hash = "sha256:704098302473cb31a218f1775a873b376b30b4c18229421e9e9dc8916fd16150"},
{file = "mypy-0.920-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:41f3575b20714171c832d8f6c7aaaa0d499c9a2d1b8adaaf837b4c9065c38540"},
{file = "mypy-0.920-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:431be889ffc8d9681813a45575c42e341c19467cbfa6dd09bf41467631feb530"},
{file = "mypy-0.920-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f8b2059f73878e92eff7ed11a03515d6572f4338a882dd7547b5f7dd242118e6"},
{file = "mypy-0.920-cp310-cp310-win_amd64.whl", hash = "sha256:9cd316e9705555ca6a50670ba5fb0084d756d1d8cb1697c83820b1456b0bc5f3"},
{file = "mypy-0.920-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e091fe58b4475b3504dc7c3022ff7f4af2f9e9ddf7182047111759ed0973bbde"},
{file = "mypy-0.920-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98b4f91a75fed2e4c6339e9047aba95968d3a7c4b91e92ab9dc62c0c583564f4"},
{file = "mypy-0.920-cp36-cp36m-win_amd64.whl", hash = "sha256:562a0e335222d5bbf5162b554c3afe3745b495d67c7fe6f8b0d1b5bace0c1eeb"},
{file = "mypy-0.920-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:618e677aabd21f30670bffb39a885a967337f5b112c6fb7c79375e6dced605d6"},
{file = "mypy-0.920-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40cb062f1b7ff4cd6e897a89d8ddc48c6ad7f326b5277c93a8c559564cc1551c"},
{file = "mypy-0.920-cp37-cp37m-win_amd64.whl", hash = "sha256:69b5a835b12fdbfeed84ef31152d41343d32ccb2b345256d8682324409164330"},
{file = "mypy-0.920-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:993c2e52ea9570e6e872296c046c946377b9f5e89eeb7afea2a1524cf6e50b27"},
{file = "mypy-0.920-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:df0fec878ccfcb2d1d2306ba31aa757848f681e7bbed443318d9bbd4b0d0fe9a"},
{file = "mypy-0.920-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:331a81d2c9bf1be25317260a073b41f4584cd11701a7c14facef0aa5a005e843"},
{file = "mypy-0.920-cp38-cp38-win_amd64.whl", hash = "sha256:ffb1e57ec49a30e3c0ebcfdc910ae4aceb7afb649310b7355509df6b15bd75f6"},
{file = "mypy-0.920-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:31895b0b3060baf15bf76e789d94722c026f673b34b774bba9e8772295edccff"},
{file = "mypy-0.920-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:140174e872d20d4768124a089b9f9fc83abd6a349b7f8cc6276bc344eb598922"},
{file = "mypy-0.920-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:13b3c110309b53f5a62aa1b360f598124be33a42563b790a2a9efaacac99f1fc"},
{file = "mypy-0.920-cp39-cp39-win_amd64.whl", hash = "sha256:82e6c15675264e923b60a11d6eb8f90665504352e68edfbb4a79aac7a04caddd"},
{file = "mypy-0.920-py3-none-any.whl", hash = "sha256:71c77bd885d2ce44900731d4652d0d1c174dc66a0f11200e0c680bdedf1a6b37"},
{file = "mypy-0.920.tar.gz", hash = "sha256:a55438627f5f546192f13255a994d6d1cf2659df48adcf966132b4379fd9c86b"},
]
mypy-extensions = [
{file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
@ -1927,57 +1914,6 @@ redis = [
{file = "redis-3.5.3-py2.py3-none-any.whl", hash = "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"},
{file = "redis-3.5.3.tar.gz", hash = "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2"},
]
regex = [
{file = "regex-2021.11.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9345b6f7ee578bad8e475129ed40123d265464c4cfead6c261fd60fc9de00bcf"},
{file = "regex-2021.11.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:416c5f1a188c91e3eb41e9c8787288e707f7d2ebe66e0a6563af280d9b68478f"},
{file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0538c43565ee6e703d3a7c3bdfe4037a5209250e8502c98f20fea6f5fdf2965"},
{file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee1227cf08b6716c85504aebc49ac827eb88fcc6e51564f010f11a406c0a667"},
{file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6650f16365f1924d6014d2ea770bde8555b4a39dc9576abb95e3cd1ff0263b36"},
{file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30ab804ea73972049b7a2a5c62d97687d69b5a60a67adca07eb73a0ddbc9e29f"},
{file = "regex-2021.11.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68a067c11463de2a37157930d8b153005085e42bcb7ad9ca562d77ba7d1404e0"},
{file = "regex-2021.11.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:162abfd74e88001d20cb73ceaffbfe601469923e875caf9118333b1a4aaafdc4"},
{file = "regex-2021.11.10-cp310-cp310-win32.whl", hash = "sha256:98ba568e8ae26beb726aeea2273053c717641933836568c2a0278a84987b2a1a"},
{file = "regex-2021.11.10-cp310-cp310-win_amd64.whl", hash = "sha256:780b48456a0f0ba4d390e8b5f7c661fdd218934388cde1a974010a965e200e12"},
{file = "regex-2021.11.10-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:dba70f30fd81f8ce6d32ddeef37d91c8948e5d5a4c63242d16a2b2df8143aafc"},
{file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1f54b9b4b6c53369f40028d2dd07a8c374583417ee6ec0ea304e710a20f80a0"},
{file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fbb9dc00e39f3e6c0ef48edee202f9520dafb233e8b51b06b8428cfcb92abd30"},
{file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666abff54e474d28ff42756d94544cdfd42e2ee97065857413b72e8a2d6a6345"},
{file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5537f71b6d646f7f5f340562ec4c77b6e1c915f8baae822ea0b7e46c1f09b733"},
{file = "regex-2021.11.10-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2e07c6a26ed4bea91b897ee2b0835c21716d9a469a96c3e878dc5f8c55bb23"},
{file = "regex-2021.11.10-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ca5f18a75e1256ce07494e245cdb146f5a9267d3c702ebf9b65c7f8bd843431e"},
{file = "regex-2021.11.10-cp36-cp36m-win32.whl", hash = "sha256:93a5051fcf5fad72de73b96f07d30bc29665697fb8ecdfbc474f3452c78adcf4"},
{file = "regex-2021.11.10-cp36-cp36m-win_amd64.whl", hash = "sha256:b483c9d00a565633c87abd0aaf27eb5016de23fed952e054ecc19ce32f6a9e7e"},
{file = "regex-2021.11.10-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fff55f3ce50a3ff63ec8e2a8d3dd924f1941b250b0aac3d3d42b687eeff07a8e"},
{file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e32d2a2b02ccbef10145df9135751abea1f9f076e67a4e261b05f24b94219e36"},
{file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:53db2c6be8a2710b359bfd3d3aa17ba38f8aa72a82309a12ae99d3c0c3dcd74d"},
{file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2207ae4f64ad3af399e2d30dde66f0b36ae5c3129b52885f1bffc2f05ec505c8"},
{file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5ca078bb666c4a9d1287a379fe617a6dccd18c3e8a7e6c7e1eb8974330c626a"},
{file = "regex-2021.11.10-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd33eb9bdcfbabab3459c9ee651d94c842bc8a05fabc95edf4ee0c15a072495e"},
{file = "regex-2021.11.10-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05b7d6d7e64efe309972adab77fc2af8907bb93217ec60aa9fe12a0dad35874f"},
{file = "regex-2021.11.10-cp37-cp37m-win32.whl", hash = "sha256:e71255ba42567d34a13c03968736c5d39bb4a97ce98188fafb27ce981115beec"},
{file = "regex-2021.11.10-cp37-cp37m-win_amd64.whl", hash = "sha256:07856afef5ffcc052e7eccf3213317fbb94e4a5cd8177a2caa69c980657b3cb4"},
{file = "regex-2021.11.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba05430e819e58544e840a68b03b28b6d328aff2e41579037e8bab7653b37d83"},
{file = "regex-2021.11.10-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7f301b11b9d214f83ddaf689181051e7f48905568b0c7017c04c06dfd065e244"},
{file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aaa4e0705ef2b73dd8e36eeb4c868f80f8393f5f4d855e94025ce7ad8525f50"},
{file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:788aef3549f1924d5c38263104dae7395bf020a42776d5ec5ea2b0d3d85d6646"},
{file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f8af619e3be812a2059b212064ea7a640aff0568d972cd1b9e920837469eb3cb"},
{file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85bfa6a5413be0ee6c5c4a663668a2cad2cbecdee367630d097d7823041bdeec"},
{file = "regex-2021.11.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f23222527b307970e383433daec128d769ff778d9b29343fb3496472dc20dabe"},
{file = "regex-2021.11.10-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:da1a90c1ddb7531b1d5ff1e171b4ee61f6345119be7351104b67ff413843fe94"},
{file = "regex-2021.11.10-cp38-cp38-win32.whl", hash = "sha256:0617383e2fe465732af4509e61648b77cbe3aee68b6ac8c0b6fe934db90be5cc"},
{file = "regex-2021.11.10-cp38-cp38-win_amd64.whl", hash = "sha256:a3feefd5e95871872673b08636f96b61ebef62971eab044f5124fb4dea39919d"},
{file = "regex-2021.11.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f7f325be2804246a75a4f45c72d4ce80d2443ab815063cdf70ee8fb2ca59ee1b"},
{file = "regex-2021.11.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:537ca6a3586931b16a85ac38c08cc48f10fc870a5b25e51794c74df843e9966d"},
{file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eef2afb0fd1747f33f1ee3e209bce1ed582d1896b240ccc5e2697e3275f037c7"},
{file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:432bd15d40ed835a51617521d60d0125867f7b88acf653e4ed994a1f8e4995dc"},
{file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b43c2b8a330a490daaef5a47ab114935002b13b3f9dc5da56d5322ff218eeadb"},
{file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:962b9a917dd7ceacbe5cd424556914cb0d636001e393b43dc886ba31d2a1e449"},
{file = "regex-2021.11.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fa8c626d6441e2d04b6ee703ef2d1e17608ad44c7cb75258c09dd42bacdfc64b"},
{file = "regex-2021.11.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3c5fb32cc6077abad3bbf0323067636d93307c9fa93e072771cf9a64d1c0f3ef"},
{file = "regex-2021.11.10-cp39-cp39-win32.whl", hash = "sha256:3b5df18db1fccd66de15aa59c41e4f853b5df7550723d26aa6cb7f40e5d9da5a"},
{file = "regex-2021.11.10-cp39-cp39-win_amd64.whl", hash = "sha256:83ee89483672b11f8952b158640d0c0ff02dc43d9cb1b70c1564b49abe92ce29"},
{file = "regex-2021.11.10.tar.gz", hash = "sha256:f341ee2df0999bfdf7a95e448075effe0db212a59387de1a70690e4acb03d4c6"},
]
requests = [
{file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"},
{file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"},
@ -2046,42 +1982,41 @@ sphinxcontrib-serializinghtml = [
{file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"},
]
sqlalchemy = [
{file = "SQLAlchemy-1.4.27-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:6afa9e4e63f066e0fd90a21db7e95e988d96127f52bfb298a0e9bec6999357a9"},
{file = "SQLAlchemy-1.4.27-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ec1c908fa721f2c5684900cc8ff75555b1a5a2ae4f5a5694eb0e37a5263cea44"},
{file = "SQLAlchemy-1.4.27-cp27-cp27m-win32.whl", hash = "sha256:0438bccc16349db2d5203598be6073175ce16d4e53b592d6e6cef880c197333e"},
{file = "SQLAlchemy-1.4.27-cp27-cp27m-win_amd64.whl", hash = "sha256:435b1980c1333ffe3ab386ad28d7b209590b0fa83ea8544d853e7a22f957331b"},
{file = "SQLAlchemy-1.4.27-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:486f7916ef77213103467924ef25f5ea1055ae901f385fe4d707604095fdf6a9"},
{file = "SQLAlchemy-1.4.27-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:d81c84c9d2523b3ea20f8e3aceea68615768a7464c0f9a9899600ce6592ec570"},
{file = "SQLAlchemy-1.4.27-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5881644fc51af7b232ab8d64f75c0f32295dfe88c2ee188023795cdbd4cf99b"},
{file = "SQLAlchemy-1.4.27-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:24828c5e74882cf41516740c0b150702bee4c6817d87d5c3d3bafef2e6896f80"},
{file = "SQLAlchemy-1.4.27-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7d0a1b1258efff7d7f2e6cfa56df580d09ba29d35a1e3f604f867e1f685feb2"},
{file = "SQLAlchemy-1.4.27-cp310-cp310-win32.whl", hash = "sha256:aadc6d1e58e14010ae4764d1ba1fd0928dbb9423b27a382ea3a1444f903f4084"},
{file = "SQLAlchemy-1.4.27-cp310-cp310-win_amd64.whl", hash = "sha256:9134e5810262203388b203c2022bbcbf1a22e89861eef9340e772a73dd9076fa"},
{file = "SQLAlchemy-1.4.27-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:fa52534076394af7315306a8701b726a6521b591d95e8f4e5121c82f94790e8d"},
{file = "SQLAlchemy-1.4.27-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2717ceae35e71de1f58b0d1ee7e773d3aab5c403c6e79e8d262277c7f7f95269"},
{file = "SQLAlchemy-1.4.27-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2e93624d186ea7a738ada47314701c8830e0e4b021a6bce7fbe6f39b87ee1516"},
{file = "SQLAlchemy-1.4.27-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:987fe2f84ceaf744fa0e48805152abe485a9d7002c9923b18a4b2529c7bff218"},
{file = "SQLAlchemy-1.4.27-cp36-cp36m-win32.whl", hash = "sha256:2146ef996181e3d4dd20eaf1d7325eb62d6c8aa4dc1677c1872ddfa8561a47d9"},
{file = "SQLAlchemy-1.4.27-cp36-cp36m-win_amd64.whl", hash = "sha256:ad8ec6b69d03e395db48df8991aa15fce3cd23e378b73e01d46a26a6efd5c26d"},
{file = "SQLAlchemy-1.4.27-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:52f23a76544ed29573c0f3ee41f0ca1aedbab3a453102b60b540cc6fa55448ad"},
{file = "SQLAlchemy-1.4.27-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd421a14edf73cfe01e8f51ed8966294ee3b3db8da921cacc88e497fd6e977af"},
{file = "SQLAlchemy-1.4.27-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:10230364479429437f1b819a8839f1edc5744c018bfeb8d01320930f97695bc9"},
{file = "SQLAlchemy-1.4.27-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78943451ab3ffd0e27876f9cea2b883317518b418f06b90dadf19394534637e9"},
{file = "SQLAlchemy-1.4.27-cp37-cp37m-win32.whl", hash = "sha256:a81e40dfa50ed3c472494adadba097640bfcf43db160ed783132045eb2093cb1"},
{file = "SQLAlchemy-1.4.27-cp37-cp37m-win_amd64.whl", hash = "sha256:015511c52c650eebf1059ed8a21674d9d4ae567ebfd80fc73f8252faccd71864"},
{file = "SQLAlchemy-1.4.27-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:cc49fb8ff103900c20e4a9c53766c82a7ebbc183377fb357a8298bad216e9cdd"},
{file = "SQLAlchemy-1.4.27-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9369f927f4d19b58322cfea8a51710a3f7c47a0e7f3398d94a4632760ecd74f6"},
{file = "SQLAlchemy-1.4.27-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6510f4a5029643301bdfe56b61e806093af2101d347d485c42a5535847d2c699"},
{file = "SQLAlchemy-1.4.27-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:771eca9872b47a629010665ff92de1c248a6979b8d1603daced37773d6f6e365"},
{file = "SQLAlchemy-1.4.27-cp38-cp38-win32.whl", hash = "sha256:4d1d707b752137e6bf45720648e1b828d5e4881d690df79cca07f7217ea06365"},
{file = "SQLAlchemy-1.4.27-cp38-cp38-win_amd64.whl", hash = "sha256:c035184af4e58e154b0977eea52131edd096e0754a88f7d5a847e7ccb3510772"},
{file = "SQLAlchemy-1.4.27-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:bac949be7579fed824887eed6672f44b7c4318abbfb2004b2c6968818b535a2f"},
{file = "SQLAlchemy-1.4.27-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ac8306e04275d382d6393e557047b0a9d7ddf9f7ca5da9b3edbd9323ea75bd9"},
{file = "SQLAlchemy-1.4.27-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8327e468b1775c0dfabc3d01f39f440585bf4d398508fcbbe2f0d931c502337d"},
{file = "SQLAlchemy-1.4.27-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b02eee1577976acb4053f83d32b7826424f8b9f70809fa756529a52c6537eda4"},
{file = "SQLAlchemy-1.4.27-cp39-cp39-win32.whl", hash = "sha256:5beeff18b4e894f6cb73c8daf2c0d8768844ef40d97032bb187d75b1ec8de24b"},
{file = "SQLAlchemy-1.4.27-cp39-cp39-win_amd64.whl", hash = "sha256:8dbe5f639e6d035778ebf700be6d573f82a13662c3c2c3aa0f1dba303b942806"},
{file = "SQLAlchemy-1.4.27.tar.gz", hash = "sha256:d768359daeb3a86644f3854c6659e4496a3e6bba2b4651ecc87ce7ad415b320c"},
{file = "SQLAlchemy-1.4.28-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:e659f256b7d402338563913bdeba53bf1eadd4c09e6f6dc93cc47938f7962a8f"},
{file = "SQLAlchemy-1.4.28-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:38df997ffa9007e953ad574f2263f61b9b683fd63ae397480ea4960be9bda0fd"},
{file = "SQLAlchemy-1.4.28-cp27-cp27m-win_amd64.whl", hash = "sha256:6dd6fa51cf08d9433d28802228d2204e175324f1a284c4492e4af2dd36a2d485"},
{file = "SQLAlchemy-1.4.28-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:bb2d8530b7cc94b7fd9341843c3e49b6db48ea22313a8db9df21c41615b5e7b1"},
{file = "SQLAlchemy-1.4.28-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:3b64f5d1c1d0e5f2ed4aa66f2b65ff6bdcdf4c5cc83b71c4bbf69695b09e9e19"},
{file = "SQLAlchemy-1.4.28-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c02991e22ddce134ef1093ef5a9d5de448fc87b91432e4f879826e93cd1c7"},
{file = "SQLAlchemy-1.4.28-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:387365c157e96eceacdd6c5468815ad05a523ba778680de4c8139a029e1fe044"},
{file = "SQLAlchemy-1.4.28-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5639800f1cfe751569af2242041b30a08a6c0b9e5d95ed674ec8082d381eff13"},
{file = "SQLAlchemy-1.4.28-cp310-cp310-win32.whl", hash = "sha256:261fcb3ff8c59e17ec44f9e61713a44ceaa97ae816da978d5cd1dc2c36f32478"},
{file = "SQLAlchemy-1.4.28-cp310-cp310-win_amd64.whl", hash = "sha256:29d10796e5604ab7bc067eda7231a2d2411a51eda43082673641245a49d1c4bb"},
{file = "SQLAlchemy-1.4.28-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:4490b10f83cd56ca2cdcd94b140d89911ac331e42a727b79157963b1b04fdd0c"},
{file = "SQLAlchemy-1.4.28-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83ee7f6fa5faed23996c67044376d46815f65183ad6d744d94d68b18cdef060b"},
{file = "SQLAlchemy-1.4.28-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f667a947378bcb12a371ab38bed1b708f3a682d1ba30176422652082919285a2"},
{file = "SQLAlchemy-1.4.28-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61965abc63c8b54038574698888e91a126753a4bdc0ec001397acb14501834e0"},
{file = "SQLAlchemy-1.4.28-cp36-cp36m-win32.whl", hash = "sha256:41a02030f8934b0de843341e7014192a0c16ee2726a06da154c81153fbe56b33"},
{file = "SQLAlchemy-1.4.28-cp36-cp36m-win_amd64.whl", hash = "sha256:c3497cd63c5f90112b8882ea4dd694052166f779ce9055cd5c4305e0b76d72d9"},
{file = "SQLAlchemy-1.4.28-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:5d91dce14ac3347bce301062ca825e7fb7e15c133f3909f15989e94878b1082f"},
{file = "SQLAlchemy-1.4.28-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08e39d65b38d4c3f77c4c9bf090b0ba4ec5721a6e0a74b63d2a9781cdcacf142"},
{file = "SQLAlchemy-1.4.28-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c85ead1d17acc5e8b282c578394dba253728bcbcbeb66e4ef0e25f4bab53935a"},
{file = "SQLAlchemy-1.4.28-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:daddcd6ba1706cc5fcc9cfaa913aa4bf331172dc7efd385fe3ee1feae3b513bc"},
{file = "SQLAlchemy-1.4.28-cp37-cp37m-win32.whl", hash = "sha256:ce4f2b34378561bc2e42635888fe86efe13d104ba1d95b5ca67b4d60d8e53e67"},
{file = "SQLAlchemy-1.4.28-cp37-cp37m-win_amd64.whl", hash = "sha256:4999b03daa6c9afb9a0bf9e3b8769128ef1880557dacfca86fa7562920c49f6b"},
{file = "SQLAlchemy-1.4.28-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:dd041324328cece3ccdf70cfbd71b5ab968e564a22318ffd88b054f5eadeb9be"},
{file = "SQLAlchemy-1.4.28-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf2c1d64c4ee0f30e08e1844ff0acf3c1b6c4277c0e89ec3e8bf1722d245b108"},
{file = "SQLAlchemy-1.4.28-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:525e962af8f25fc24ce019e6f237d49f8720d757a8a56c9b4caa2d91e2c66111"},
{file = "SQLAlchemy-1.4.28-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b72744fed32ecf2bf786d2e2f6756c04126c323ba939f47177b9722775626889"},
{file = "SQLAlchemy-1.4.28-cp38-cp38-win32.whl", hash = "sha256:b5541355b8d4970753d4f7292f73a320704b20406e06cd29b469d156f0a484d8"},
{file = "SQLAlchemy-1.4.28-cp38-cp38-win_amd64.whl", hash = "sha256:cf3a3c2f32d53a4166b2eb8de35f93bcb640e51c32033024af500017d8e8a8c9"},
{file = "SQLAlchemy-1.4.28-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:dfa093bd8ecfceafff62078910178567323005e44fbe4d7933e6cbce4512cea2"},
{file = "SQLAlchemy-1.4.28-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:555d56b71f61b4c9fa55fe203fe6e1e561c9385fa97c5849783ae050a89113af"},
{file = "SQLAlchemy-1.4.28-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c90b21360cf14d33c8a004f991aa336c7906a8db825d4ec38722c5ff1c47dada"},
{file = "SQLAlchemy-1.4.28-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2019b332cf4f9a513133fdf056dc4cecec7fbae7016ebc574d0f310103eed7ee"},
{file = "SQLAlchemy-1.4.28-cp39-cp39-win32.whl", hash = "sha256:ca500f30619daf863ab1c66d57d53a0987361a8f3266454290198aabd18f2599"},
{file = "SQLAlchemy-1.4.28-cp39-cp39-win_amd64.whl", hash = "sha256:853de08e881dae0305647dd61b4429758f11d1bf02a9faf02793cad44bb2e0d5"},
{file = "SQLAlchemy-1.4.28.tar.gz", hash = "sha256:7fdb7b775fb0739d3e71461509f978beb788935bc0aa9e47df14837cb33e5226"},
]
staticmap = [
{file = "staticmap-0.5.5.tar.gz", hash = "sha256:007c507b4d42e00eaba179649753f2f8d69d4ece3028736e18d9e86493044387"},
@ -2095,8 +2030,8 @@ toml = [
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
]
tomli = [
{file = "tomli-1.2.2-py3-none-any.whl", hash = "sha256:f04066f68f5554911363063a30b108d2b5a5b1a010aa8b6132af78489fe3aade"},
{file = "tomli-1.2.2.tar.gz", hash = "sha256:c6ce0015eb38820eaf32b5db832dbc26deb3dd427bd5f6556cf0acac2c214fee"},
{file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"},
{file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"},
]
tqdm = [
{file = "tqdm-4.62.3-py2.py3-none-any.whl", hash = "sha256:8dd278a422499cd6b727e6ae4061c40b48fce8b76d1ccbf5d34fca9b7f925b0c"},
@ -2111,52 +2046,41 @@ trio-websocket = [
{file = "trio_websocket-0.9.2-py3-none-any.whl", hash = "sha256:5b558f6e83cc20a37c3b61202476c5295d1addf57bd65543364e0337e37ed2bc"},
]
typed-ast = [
{file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"},
{file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"},
{file = "typed_ast-1.4.3-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528"},
{file = "typed_ast-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428"},
{file = "typed_ast-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3"},
{file = "typed_ast-1.4.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f"},
{file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341"},
{file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace"},
{file = "typed_ast-1.4.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f"},
{file = "typed_ast-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363"},
{file = "typed_ast-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7"},
{file = "typed_ast-1.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266"},
{file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e"},
{file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04"},
{file = "typed_ast-1.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899"},
{file = "typed_ast-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c"},
{file = "typed_ast-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805"},
{file = "typed_ast-1.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a"},
{file = "typed_ast-1.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff"},
{file = "typed_ast-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41"},
{file = "typed_ast-1.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39"},
{file = "typed_ast-1.4.3-cp38-cp38-win32.whl", hash = "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927"},
{file = "typed_ast-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40"},
{file = "typed_ast-1.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3"},
{file = "typed_ast-1.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4"},
{file = "typed_ast-1.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0"},
{file = "typed_ast-1.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3"},
{file = "typed_ast-1.4.3-cp39-cp39-win32.whl", hash = "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808"},
{file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"},
{file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"},
{file = "typed_ast-1.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d8314c92414ce7481eee7ad42b353943679cf6f30237b5ecbf7d835519e1212"},
{file = "typed_ast-1.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b53ae5de5500529c76225d18eeb060efbcec90ad5e030713fe8dab0fb4531631"},
{file = "typed_ast-1.5.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:24058827d8f5d633f97223f5148a7d22628099a3d2efe06654ce872f46f07cdb"},
{file = "typed_ast-1.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:a6d495c1ef572519a7bac9534dbf6d94c40e5b6a608ef41136133377bba4aa08"},
{file = "typed_ast-1.5.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:de4ecae89c7d8b56169473e08f6bfd2df7f95015591f43126e4ea7865928677e"},
{file = "typed_ast-1.5.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:256115a5bc7ea9e665c6314ed6671ee2c08ca380f9d5f130bd4d2c1f5848d695"},
{file = "typed_ast-1.5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:7c42707ab981b6cf4b73490c16e9d17fcd5227039720ca14abe415d39a173a30"},
{file = "typed_ast-1.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:71dcda943a471d826ea930dd449ac7e76db7be778fcd722deb63642bab32ea3f"},
{file = "typed_ast-1.5.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4f30a2bcd8e68adbb791ce1567fdb897357506f7ea6716f6bbdd3053ac4d9471"},
{file = "typed_ast-1.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ca9e8300d8ba0b66d140820cf463438c8e7b4cdc6fd710c059bfcfb1531d03fb"},
{file = "typed_ast-1.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9caaf2b440efb39ecbc45e2fabde809cbe56272719131a6318fd9bf08b58e2cb"},
{file = "typed_ast-1.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c9bcad65d66d594bffab8575f39420fe0ee96f66e23c4d927ebb4e24354ec1af"},
{file = "typed_ast-1.5.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:591bc04e507595887160ed7aa8d6785867fb86c5793911be79ccede61ae96f4d"},
{file = "typed_ast-1.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:a80d84f535642420dd17e16ae25bb46c7f4c16ee231105e7f3eb43976a89670a"},
{file = "typed_ast-1.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:38cf5c642fa808300bae1281460d4f9b7617cf864d4e383054a5ef336e344d32"},
{file = "typed_ast-1.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5b6ab14c56bc9c7e3c30228a0a0b54b915b1579613f6e463ba6f4eb1382e7fd4"},
{file = "typed_ast-1.5.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2b8d7007f6280e36fa42652df47087ac7b0a7d7f09f9468f07792ba646aac2d"},
{file = "typed_ast-1.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:b6d17f37f6edd879141e64a5db17b67488cfeffeedad8c5cec0392305e9bc775"},
{file = "typed_ast-1.5.1.tar.gz", hash = "sha256:484137cab8ecf47e137260daa20bafbba5f4e3ec7fda1c1e69ab299b75fa81c5"},
]
types-freezegun = [
{file = "types-freezegun-1.1.3.tar.gz", hash = "sha256:eb12cd460cb9ed9a0674c6f2c799763f85650db59b00f2918ff55bc11e1be2ae"},
{file = "types_freezegun-1.1.3-py3-none-any.whl", hash = "sha256:e072fd10fbc4dd7f28f33c094ccb36f9578e1e96f70b01f2ed3f214f0383e6e8"},
]
types-pytz = [
{file = "types-pytz-2021.3.1.tar.gz", hash = "sha256:dffd77f3efecd3b1555f187a9bf3a638d55fac296700b829c41bd51ec72a6eb7"},
{file = "types_pytz-2021.3.1-py3-none-any.whl", hash = "sha256:d58a0688094b768d8e21c044e45861cbcaecba0494fd5b9c5feb3e1739211606"},
{file = "types-pytz-2021.3.3.tar.gz", hash = "sha256:f6d21d6687935a1615db464b1e1df800d19502c36bc0486f43be7dfd2c404947"},
{file = "types_pytz-2021.3.3-py3-none-any.whl", hash = "sha256:75859c64c9a97d68259af6da208e8f5aaf4be4536e4d431a82a6e8b848fc183d"},
]
types-requests = [
{file = "types-requests-2.26.1.tar.gz", hash = "sha256:0893e112e1510bbb67f537941c92192de7472e51bf7f236e0e583866f0ed933e"},
{file = "types_requests-2.26.1-py3-none-any.whl", hash = "sha256:853571b3accc188976c0f4feffcaebf6cdfc170082b5e43f3358aa78de61f531"},
{file = "types-requests-2.26.2.tar.gz", hash = "sha256:0e22d9cdeff4c3eb068eb883d59b127c98d80525f3d0412a1c4499c6ae1f711e"},
{file = "types_requests-2.26.2-py3-none-any.whl", hash = "sha256:fabe1acc784708ac798ced6373568465b93642c8aa1ebd33e2921b60d4e7aa29"},
]
typing-extensions = [
{file = "typing_extensions-4.0.0-py3-none-any.whl", hash = "sha256:829704698b22e13ec9eaf959122315eabb370b0884400e9818334d8b677023d9"},
{file = "typing_extensions-4.0.0.tar.gz", hash = "sha256:2cdf80e4e04866a9b3689a51869016d36db0814d84b8d8a568d22781d45d27ed"},
{file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"},
{file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"},
]
urllib3 = [
{file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"},

View File

@ -1,9 +1,9 @@
[tool.poetry]
name = "fittrackee"
version = "0.5.1"
version = "0.5.2"
description = "Self-hosted outdoor workout/activity tracker"
authors = ["SamR1"]
license = "GPL-3.0"
license = "AGPL-3.0"
readme = "README.md"
homepage = "https://github.com/SamR1/FitTrackee"
documentation = "https://samr1.github.io/FitTrackee"
@ -31,7 +31,7 @@ flask-dramatiq = "^0.6.0"
flask-migrate = "^3.1"
gpxpy = "=1.3.4"
gunicorn = "^20.1"
humanize = "^3.12"
humanize = "^3.13"
psycopg2-binary = "^2.9"
pyjwt = "^2.3"
python-forecastio = "^1.4"
@ -39,12 +39,12 @@ pytz = "^2021.3"
shortuuid = "^1.0.8"
staticmap = "^0.5.4"
tqdm = "^4.62"
SQLAlchemy = "1.4.27"
SQLAlchemy = "1.4.28"
[tool.poetry.dev-dependencies]
black = "^21.11b1"
black = "^21.12b0"
freezegun = "^1.1"
mypy = "^0.910"
mypy = "^0.920"
pyopenssl = "^20.0"
pytest = "^6.2"
pytest-black = "^0.3.12"
@ -56,8 +56,8 @@ pytest-selenium = "^2.0.1"
recommonmark = "^0.7"
sphinx-bootstrap-theme = "^0.8.0"
sphinxcontrib-httpdomain = "^1.7"
types-pytz = "^2021.3.1"
types-requests = "^2.26.1"
types-pytz = "^2021.3"
types-requests = "^2.26"
types-freezegun = "^1.1"
Sphinx = "^4.3"