Merge pull request #249 from SamR1/postgresql15-support

Add PostgreSQL 15 support
This commit is contained in:
Sam 2022-10-31 08:15:42 +01:00 committed by GitHub
commit 3ec5257685
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 152 additions and 94 deletions

View File

@ -15,12 +15,12 @@ env:
jobs: jobs:
python: python:
name: python ${{ matrix.python-version }} name: python ${{ matrix.python-version }} (postgresql 14)
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: python:${{ matrix.python-version }} container: python:${{ matrix.python-version }}
services: services:
postgres: postgres:
image: postgres:latest image: postgres:14
env: env:
POSTGRES_DB: fittrackee_test POSTGRES_DB: fittrackee_test
POSTGRES_USER: fittrackee POSTGRES_USER: fittrackee
@ -32,7 +32,7 @@ jobs:
--health-retries 5 --health-retries 5
strategy: strategy:
matrix: matrix:
python-version: [ "3.7", "3.8", "3.9", "3.10" ] python-version: [ "3.7", "3.8", "3.9", "3.10", "3.11" ]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install Poetry and Dependencies - name: Install Poetry and Dependencies
@ -53,13 +53,43 @@ jobs:
- name: Pytest - name: Pytest
run: pytest fittrackee -p no:warnings --cov fittrackee --cov-report term-missing run: pytest fittrackee -p no:warnings --cov fittrackee --cov-report term-missing
postgresql:
name: postgresql ${{ matrix.psql-version }} (python 3.10)
runs-on: ubuntu-latest
container: python:3.10
services:
postgres:
image: postgres:${{ matrix.psql-version }}
env:
POSTGRES_DB: fittrackee_test
POSTGRES_USER: fittrackee
POSTGRES_PASSWORD: fittrackee
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
strategy:
matrix:
psql-version: [ "10", "11", "12", "13", "15" ]
steps:
- uses: actions/checkout@v2
- name: Install Poetry and Dependencies
run: |
python -m pip install --upgrade pip
pip install --quiet poetry
poetry config virtualenvs.create false
poetry install --no-interaction --quiet
- name: Pytest
run: pytest fittrackee -p no:warnings --cov fittrackee --cov-report term-missing
end2end: end2end:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: ["python"] needs: ["python"]
container: python:3.10 container: python:3.10
services: services:
postgres: postgres:
image: postgres:latest image: postgres:14
env: env:
POSTGRES_DB: fittrackee_test POSTGRES_DB: fittrackee_test
POSTGRES_USER: fittrackee POSTGRES_USER: fittrackee

View File

@ -1,9 +1,9 @@
DROP DATABASE IF EXISTS fittrackee; DROP DATABASE IF EXISTS fittrackee;
DROP DATABASE IF EXISTS fittrackee_test; DROP DATABASE IF EXISTS fittrackee_test;
DROP SCHEMA IF EXISTS fittrackee;
DROP USER IF EXISTS fittrackee; DROP USER IF EXISTS fittrackee;
CREATE DATABASE fittrackee;
CREATE DATABASE fittrackee_test;
CREATE USER fittrackee WITH PASSWORD 'fittrackee'; CREATE USER fittrackee WITH PASSWORD 'fittrackee';
GRANT ALL PRIVILEGES ON DATABASE fittrackee TO fittrackee; CREATE SCHEMA fittrackee AUTHORIZATION fittrackee;
GRANT ALL PRIVILEGES ON DATABASE fittrackee_test TO fittrackee; CREATE DATABASE fittrackee OWNER fittrackee;
CREATE DATABASE fittrackee_test OWNER fittrackee;

View File

@ -364,9 +364,12 @@ Example :
.. code-block:: sql .. code-block:: sql
CREATE DATABASE fittrackee;
CREATE USER fittrackee WITH PASSWORD '<PASSWORD>'; CREATE USER fittrackee WITH PASSWORD '<PASSWORD>';
GRANT ALL PRIVILEGES ON DATABASE fittrackee TO fittrackee; CREATE SCHEMA fittrackee AUTHORIZATION fittrackee;
CREATE DATABASE fittrackee OWNER fittrackee;
.. note::
| see PostgreSQL `documentation <https://www.postgresql.org/docs/15/ddl-schemas.html>`_ for schema and privileges.
- Initialize environment variables, see `Environment variables <installation.html#environment-variables>`__ - Initialize environment variables, see `Environment variables <installation.html#environment-variables>`__

View File

@ -265,9 +265,10 @@ has admin rights.</p>
<li><p><strong>page</strong> (<em>integer</em>) page if using pagination (default: 1)</p></li> <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>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> <li><p><strong>q</strong> (<em>string</em>) query on user name</p></li>
<li><p><strong>order_by</strong> (<em>string</em>) sorting criteria (<code class="docutils literal notranslate"><span class="pre">username</span></code>, <code class="docutils literal notranslate"><span class="pre">created_at</span></code>, <li><p><strong>order</strong> (<em>string</em>) sorting order: <code class="docutils literal notranslate"><span class="pre">asc</span></code>, <code class="docutils literal notranslate"><span class="pre">desc</span></code> (default: <code class="docutils literal notranslate"><span class="pre">asc</span></code>)</p></li>
<code class="docutils literal notranslate"><span class="pre">workouts_count</span></code>, <code class="docutils literal notranslate"><span class="pre">admin</span></code>, <code class="docutils literal notranslate"><span class="pre">is_active</span></code>)</p></li> <li><p><strong>order_by</strong> (<em>string</em>) sorting criteria: <code class="docutils literal notranslate"><span class="pre">username</span></code>, <code class="docutils literal notranslate"><span class="pre">created_at</span></code>,
<li><p><strong>order</strong> (<em>string</em>) sorting order (default: <code class="docutils literal notranslate"><span class="pre">asc</span></code>)</p></li> <code class="docutils literal notranslate"><span class="pre">workouts_count</span></code>, <code class="docutils literal notranslate"><span class="pre">admin</span></code>, <code class="docutils literal notranslate"><span class="pre">is_active</span></code>
(default: <code class="docutils literal notranslate"><span class="pre">username</span></code>)</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers<span class="colon">:</span></dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>

View File

@ -270,7 +270,10 @@
<li><p><strong>ave_speed_to</strong> (<em>float</em>) maximal average speed</p></li> <li><p><strong>ave_speed_to</strong> (<em>float</em>) maximal average speed</p></li>
<li><p><strong>max_speed_from</strong> (<em>float</em>) minimal max. speed</p></li> <li><p><strong>max_speed_from</strong> (<em>float</em>) minimal max. speed</p></li>
<li><p><strong>max_speed_to</strong> (<em>float</em>) maximal max. speed</p></li> <li><p><strong>max_speed_to</strong> (<em>float</em>) maximal max. speed</p></li>
<li><p><strong>order</strong> (<em>string</em>) sorting order (default: <code class="docutils literal notranslate"><span class="pre">desc</span></code>)</p></li> <li><p><strong>order</strong> (<em>string</em>) sorting order: <code class="docutils literal notranslate"><span class="pre">asc</span></code>, <code class="docutils literal notranslate"><span class="pre">desc</span></code> (default: <code class="docutils literal notranslate"><span class="pre">desc</span></code>)</p></li>
<li><p><strong>order_by</strong> (<em>string</em>) sorting criteria: <code class="docutils literal notranslate"><span class="pre">ave_speed</span></code>, <code class="docutils literal notranslate"><span class="pre">distance</span></code>,
<code class="docutils literal notranslate"><span class="pre">duration</span></code>, <code class="docutils literal notranslate"><span class="pre">workout_date</span></code> (default:
<code class="docutils literal notranslate"><span class="pre">workout_date</span></code>)</p></li>
</ul> </ul>
</dd> </dd>
<dt class="field-even">Request Headers<span class="colon">:</span></dt> <dt class="field-even">Request Headers<span class="colon">:</span></dt>

View File

@ -668,11 +668,17 @@ Commands:
<li><p>Create <code class="docutils literal notranslate"><span class="pre">fittrackee</span></code> database</p></li> <li><p>Create <code class="docutils literal notranslate"><span class="pre">fittrackee</span></code> database</p></li>
</ul> </ul>
<p>Example :</p> <p>Example :</p>
<div class="highlight-sql notranslate"><div class="highlight"><pre><span></span><span class="k">CREATE</span><span class="w"> </span><span class="k">DATABASE</span><span class="w"> </span><span class="n">fittrackee</span><span class="p">;</span><span class="w"></span> <div class="highlight-sql notranslate"><div class="highlight"><pre><span></span><span class="k">CREATE</span><span class="w"> </span><span class="k">USER</span><span class="w"> </span><span class="n">fittrackee</span><span class="w"> </span><span class="k">WITH</span><span class="w"> </span><span class="n">PASSWORD</span><span class="w"> </span><span class="s1">&#39;&lt;PASSWORD&gt;&#39;</span><span class="p">;</span><span class="w"></span>
<span class="k">CREATE</span><span class="w"> </span><span class="k">USER</span><span class="w"> </span><span class="n">fittrackee</span><span class="w"> </span><span class="k">WITH</span><span class="w"> </span><span class="n">PASSWORD</span><span class="w"> </span><span class="s1">&#39;&lt;PASSWORD&gt;&#39;</span><span class="p">;</span><span class="w"></span> <span class="k">CREATE</span><span class="w"> </span><span class="k">SCHEMA</span><span class="w"> </span><span class="n">fittrackee</span><span class="w"> </span><span class="k">AUTHORIZATION</span><span class="w"> </span><span class="n">fittrackee</span><span class="p">;</span><span class="w"></span>
<span class="k">GRANT</span><span class="w"> </span><span class="k">ALL</span><span class="w"> </span><span class="k">PRIVILEGES</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="k">DATABASE</span><span class="w"> </span><span class="n">fittrackee</span><span class="w"> </span><span class="k">TO</span><span class="w"> </span><span class="n">fittrackee</span><span class="p">;</span><span class="w"></span> <span class="k">CREATE</span><span class="w"> </span><span class="k">DATABASE</span><span class="w"> </span><span class="n">fittrackee</span><span class="w"> </span><span class="k">OWNER</span><span class="w"> </span><span class="n">fittrackee</span><span class="p">;</span><span class="w"></span>
</pre></div> </pre></div>
</div> </div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<div class="line-block">
<div class="line">see PostgreSQL <a class="reference external" href="https://www.postgresql.org/docs/15/ddl-schemas.html">documentation</a> for schema and privileges.</div>
</div>
</div>
<ul class="simple"> <ul class="simple">
<li><p>Initialize environment variables, see <a class="reference external" href="installation.html#environment-variables">Environment variables</a></p></li> <li><p>Initialize environment variables, see <a class="reference external" href="installation.html#environment-variables">Environment variables</a></p></li>
</ul> </ul>

File diff suppressed because one or more lines are too long

View File

@ -364,9 +364,12 @@ Example :
.. code-block:: sql .. code-block:: sql
CREATE DATABASE fittrackee;
CREATE USER fittrackee WITH PASSWORD '<PASSWORD>'; CREATE USER fittrackee WITH PASSWORD '<PASSWORD>';
GRANT ALL PRIVILEGES ON DATABASE fittrackee TO fittrackee; CREATE SCHEMA fittrackee AUTHORIZATION fittrackee;
CREATE DATABASE fittrackee OWNER fittrackee;
.. note::
| see PostgreSQL `documentation <https://www.postgresql.org/docs/15/ddl-schemas.html>`_ for schema and privileges.
- Initialize environment variables, see `Environment variables <installation.html#environment-variables>`__ - Initialize environment variables, see `Environment variables <installation.html#environment-variables>`__

View File

@ -154,7 +154,9 @@ def seven_workouts_user_1() -> List[Workout]:
workout_4 = Workout( workout_4 = Workout(
user_id=1, user_id=1,
sport_id=1, sport_id=1,
workout_date=datetime.datetime.strptime('23/02/2018', '%d/%m/%Y'), workout_date=datetime.datetime.strptime(
'23/02/2018 10:00', '%d/%m/%Y %H:%M'
),
distance=1, distance=1,
duration=datetime.timedelta(seconds=600), duration=datetime.timedelta(seconds=600),
) )

View File

@ -1,4 +1,5 @@
import json import json
from datetime import timedelta
from typing import List from typing import List
from unittest.mock import patch from unittest.mock import patch
from uuid import uuid4 from uuid import uuid4
@ -6,6 +7,7 @@ from uuid import uuid4
import pytest import pytest
from flask import Flask from flask import Flask
from fittrackee import db
from fittrackee.users.models import User from fittrackee.users.models import User
from fittrackee.workouts.models import Sport, Workout from fittrackee.workouts.models import Sport, Workout
@ -370,7 +372,7 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin):
seven_workouts_user_1[5].serialize() seven_workouts_user_1[5].serialize()
) )
assert data['data']['workouts'][2] == jsonify_dict( assert data['data']['workouts'][2] == jsonify_dict(
seven_workouts_user_1[4].serialize() seven_workouts_user_1[3].serialize()
) )
assert data['pagination'] == { assert data['pagination'] == {
'has_next': True, 'has_next': True,
@ -443,7 +445,7 @@ class TestGetWorkoutsWithOrder(ApiTestCaseMixin):
== data['data']['workouts'][0]['workout_date'] == data['data']['workouts'][0]['workout_date']
) )
assert ( assert (
'Fri, 23 Feb 2018 00:00:00 GMT' 'Fri, 23 Feb 2018 10:00:00 GMT'
== data['data']['workouts'][4]['workout_date'] == data['data']['workouts'][4]['workout_date']
) )
assert data['pagination'] == { assert data['pagination'] == {
@ -558,7 +560,7 @@ class TestGetWorkoutsWithOrderBy(ApiTestCaseMixin):
'total': 7, 'total': 7,
} }
def test_it_gets_workouts_ordered_by_duration( def test_it_gets_workouts_ordered_by_moving_time(
self, self,
app: Flask, app: Flask,
user_1: User, user_1: User,
@ -568,6 +570,10 @@ class TestGetWorkoutsWithOrderBy(ApiTestCaseMixin):
client, auth_token = self.get_test_client_and_auth_token( client, auth_token = self.get_test_client_and_auth_token(
app, user_1.email app, user_1.email
) )
seven_workouts_user_1[6].duration = seven_workouts_user_1[
6
].moving + timedelta(seconds=1000)
db.session.commit()
response = client.get( response = client.get(
'/api/workouts?order_by=duration', '/api/workouts?order_by=duration',
@ -579,7 +585,23 @@ class TestGetWorkoutsWithOrderBy(ApiTestCaseMixin):
assert 'success' in data['status'] assert 'success' in data['status']
assert len(data['data']['workouts']) == 5 assert len(data['data']['workouts']) == 5
assert '1:40:00' == data['data']['workouts'][0]['duration'] assert '1:40:00' == data['data']['workouts'][0]['duration']
assert '0:17:04' == data['data']['workouts'][4]['duration'] assert '1:40:00' == data['data']['workouts'][0]['moving']
assert (
'Sun, 01 Apr 2018 00:00:00 GMT'
== data['data']['workouts'][0]['workout_date']
)
assert '0:57:36' == data['data']['workouts'][1]['duration']
assert '0:57:36' == data['data']['workouts'][1]['moving']
assert (
'Thu, 01 Jun 2017 00:00:00 GMT'
== data['data']['workouts'][1]['workout_date']
)
assert '1:06:40' == data['data']['workouts'][2]['duration']
assert '0:50:00' == data['data']['workouts'][2]['moving']
assert (
'Wed, 09 May 2018 00:00:00 GMT'
== data['data']['workouts'][2]['workout_date']
)
assert data['pagination'] == { assert data['pagination'] == {
'has_next': True, 'has_next': True,
'has_prev': False, 'has_prev': False,
@ -642,11 +664,9 @@ class TestGetWorkoutsWithFilters(ApiTestCaseMixin):
assert len(data['data']['workouts']) == 2 assert len(data['data']['workouts']) == 2
assert 'creation_date' in data['data']['workouts'][0] assert 'creation_date' in data['data']['workouts'][0]
assert ( assert (
'Fri, 23 Feb 2018 00:00:00 GMT' 'Fri, 23 Feb 2018 10:00:00 GMT'
== data['data']['workouts'][0]['workout_date'] == data['data']['workouts'][0]['workout_date']
) )
assert '0:16:40' == data['data']['workouts'][0]['duration']
assert 'creation_date' in data['data']['workouts'][1]
assert ( assert (
'Fri, 23 Feb 2018 00:00:00 GMT' 'Fri, 23 Feb 2018 00:00:00 GMT'
== data['data']['workouts'][1]['workout_date'] == data['data']['workouts'][1]['workout_date']
@ -849,7 +869,7 @@ class TestGetWorkoutsWithFilters(ApiTestCaseMixin):
assert 'success' in data['status'] assert 'success' in data['status']
assert len(data['data']['workouts']) == 1 assert len(data['data']['workouts']) == 1
assert ( assert (
'Fri, 23 Feb 2018 00:00:00 GMT' 'Fri, 23 Feb 2018 10:00:00 GMT'
== data['data']['workouts'][0]['workout_date'] == data['data']['workouts'][0]['workout_date']
) )
assert data['pagination'] == { assert data['pagination'] == {

View File

@ -1019,8 +1019,43 @@ class TestPostWorkoutWithZipArchive(ApiTestCaseMixin):
assert response.status_code == 201 assert response.status_code == 201
assert 'created' in data['status'] assert 'created' in data['status']
assert len(data['data']['workouts']) == 3 assert len(data['data']['workouts']) == 3
assert 'just a workout' == data['data']['workouts'][0]['title'] assert 'creation_date' in data['data']['workouts'][0]
assert_workout_data_with_gpx(data) assert (
'Tue, 13 Mar 2018 12:44:45 GMT'
== data['data']['workouts'][0]['workout_date']
)
assert 'test' == data['data']['workouts'][0]['user']
assert 1 == data['data']['workouts'][0]['sport_id']
assert '0:04:10' == data['data']['workouts'][0]['duration']
assert data['data']['workouts'][0]['ascent'] == 0.4
assert data['data']['workouts'][0]['ave_speed'] == 4.61
assert data['data']['workouts'][0]['descent'] == 23.4
assert data['data']['workouts'][0]['distance'] == 0.32
assert data['data']['workouts'][0]['max_alt'] == 998.0
assert data['data']['workouts'][0]['max_speed'] == 5.12
assert data['data']['workouts'][0]['min_alt'] == 975.0
assert data['data']['workouts'][0]['moving'] == '0:04:10'
assert data['data']['workouts'][0]['pauses'] is None
assert data['data']['workouts'][0]['with_gpx'] is True
assert data['data']['workouts'][0]['map'] is not None
assert data['data']['workouts'][0]['weather_start'] is None
assert data['data']['workouts'][0]['weather_end'] is None
assert data['data']['workouts'][0]['notes'] is None
assert len(data['data']['workouts'][0]['segments']) == 1
segment = data['data']['workouts'][0]['segments'][0]
assert segment['workout_id'] == data['data']['workouts'][0]['id']
assert segment['segment_id'] == 0
assert segment['duration'] == '0:04:10'
assert segment['ascent'] == 0.4
assert segment['ave_speed'] == 4.61
assert segment['descent'] == 23.4
assert segment['distance'] == 0.32
assert segment['max_alt'] == 998.0
assert segment['max_speed'] == 5.12
assert segment['min_alt'] == 975.0
assert segment['moving'] == '0:04:10'
assert segment['pauses'] is None
def test_it_returns_400_if_folder_is_present_in_zip_archive( def test_it_returns_400_if_folder_is_present_in_zip_archive(
self, app: Flask, user_1: User, sport_1_cycling: Sport self, app: Flask, user_1: User, sport_1_cycling: Sport

View File

@ -3,7 +3,7 @@ import shutil
from typing import Any, Dict, Tuple, Union from typing import Any, Dict, Tuple, Union
from flask import Blueprint, current_app, request, send_file from flask import Blueprint, current_app, request, send_file
from sqlalchemy import exc from sqlalchemy import asc, desc, exc
from fittrackee import db, limiter from fittrackee import db, limiter
from fittrackee.emails.tasks import ( from fittrackee.emails.tasks import (
@ -173,9 +173,10 @@ def get_users(auth_user: User) -> Dict:
:query integer page: page if using pagination (default: 1) :query integer page: page if using pagination (default: 1)
:query integer per_page: number of users per page (default: 10, max: 50) :query integer per_page: number of users per page (default: 10, max: 50)
:query string q: query on user name :query string q: query on user name
:query string order_by: sorting criteria (``username``, ``created_at``, :query string order: sorting order: ``asc``, ``desc`` (default: ``asc``)
``workouts_count``, ``admin``, ``is_active``) :query string order_by: sorting criteria: ``username``, ``created_at``,
:query string order: sorting order (default: ``asc``) ``workouts_count``, ``admin``, ``is_active``
(default: ``username``)
:reqheader Authorization: OAuth 2.0 Bearer Token :reqheader Authorization: OAuth 2.0 Bearer Token
@ -191,45 +192,14 @@ def get_users(auth_user: User) -> Dict:
per_page = int(params.get('per_page', USER_PER_PAGE)) per_page = int(params.get('per_page', USER_PER_PAGE))
if per_page > 50: if per_page > 50:
per_page = 50 per_page = 50
order_by = params.get('order_by') user_column = getattr(User, params.get('order_by', 'username'))
order = params.get('order', 'asc') order = params.get('order', 'asc')
query = params.get('q') query = params.get('q')
users_pagination = ( users_pagination = (
User.query.filter( User.query.filter(
User.username.ilike('%' + query + '%') if query else True, User.username.ilike('%' + query + '%') if query else True,
) )
.order_by( .order_by(asc(user_column) if order == 'asc' else desc(user_column))
User.workouts_count.asc() # type: ignore
if order_by == 'workouts_count' and order == 'asc'
else True,
User.workouts_count.desc() # type: ignore
if order_by == 'workouts_count' and order == 'desc'
else True,
User.username.asc()
if order_by == 'username' and order == 'asc'
else True,
User.username.desc()
if order_by == 'username' and order == 'desc'
else True,
User.created_at.asc()
if order_by == 'created_at' and order == 'asc'
else True,
User.created_at.desc()
if order_by == 'created_at' and order == 'desc'
else True,
User.admin.asc()
if order_by == 'admin' and order == 'asc'
else True,
User.admin.desc()
if order_by == 'admin' and order == 'desc'
else True,
User.is_active.asc()
if order_by == 'is_active' and order == 'asc'
else True,
User.is_active.desc()
if order_by == 'is_active' and order == 'desc'
else True,
)
.paginate(page, per_page, False) .paginate(page, per_page, False)
) )
users = users_pagination.items users = users_pagination.items

View File

@ -12,7 +12,7 @@ from flask import (
request, request,
send_from_directory, send_from_directory,
) )
from sqlalchemy import exc from sqlalchemy import asc, desc, exc
from werkzeug.exceptions import NotFound, RequestEntityTooLarge from werkzeug.exceptions import NotFound, RequestEntityTooLarge
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
@ -197,7 +197,10 @@ def get_workouts(auth_user: User) -> Union[Dict, HttpResponse]:
:query float ave_speed_to: maximal average speed :query float ave_speed_to: maximal average speed
:query float max_speed_from: minimal max. speed :query float max_speed_from: minimal max. speed
:query float max_speed_to: maximal max. speed :query float max_speed_to: maximal max. speed
:query string order: sorting order (default: ``desc``) :query string order: sorting order: ``asc``, ``desc`` (default: ``desc``)
:query string order_by: sorting criteria: ``ave_speed``, ``distance``,
``duration``, ``workout_date`` (default:
``workout_date``)
:reqheader Authorization: OAuth 2.0 Bearer Token :reqheader Authorization: OAuth 2.0 Bearer Token
@ -222,6 +225,9 @@ def get_workouts(auth_user: User) -> Union[Dict, HttpResponse]:
max_speed_from = params.get('max_speed_from') max_speed_from = params.get('max_speed_from')
max_speed_to = params.get('max_speed_to') max_speed_to = params.get('max_speed_to')
order_by = params.get('order_by', 'workout_date') order_by = params.get('order_by', 'workout_date')
workout_column = getattr(
Workout, 'moving' if order_by == 'duration' else order_by
)
order = params.get('order', 'desc') order = params.get('order', 'desc')
sport_id = params.get('sport_id') sport_id = params.get('sport_id')
per_page = int(params.get('per_page', DEFAULT_WORKOUTS_PER_PAGE)) per_page = int(params.get('per_page', DEFAULT_WORKOUTS_PER_PAGE))
@ -261,30 +267,9 @@ def get_workouts(auth_user: User) -> Union[Dict, HttpResponse]:
else True, else True,
) )
.order_by( .order_by(
Workout.ave_speed.asc() asc(workout_column)
if order_by == 'ave_speed' and order == 'asc' if order == 'asc'
else True, else desc(workout_column),
Workout.ave_speed.desc()
if order_by == 'ave_speed' and order == 'desc'
else True,
Workout.distance.asc()
if order_by == 'distance' and order == 'asc'
else True,
Workout.distance.desc()
if order_by == 'distance' and order == 'desc'
else True,
Workout.moving.asc()
if order_by == 'duration' and order == 'asc'
else True,
Workout.moving.desc()
if order_by == 'duration' and order == 'desc'
else True,
Workout.workout_date.asc()
if order_by == 'workout_date' and order == 'asc'
else True,
Workout.workout_date.desc()
if order_by == 'workout_date' and order == 'desc'
else True,
) )
.paginate(page, per_page, False) .paginate(page, per_page, False)
) )