[API] add endpoint to download gpx file
This commit is contained in:
parent
76dc9f1912
commit
e50c3d3799
@ -1139,3 +1139,89 @@ class TestGetWorkout(ApiTestCaseMixin):
|
|||||||
assert response.status_code == 404
|
assert response.status_code == 404
|
||||||
assert 'not found' in data['status']
|
assert 'not found' in data['status']
|
||||||
assert 'Map does not exist' in data['message']
|
assert 'Map does not exist' in data['message']
|
||||||
|
|
||||||
|
|
||||||
|
class TestDownloadWorkoutGpx(ApiTestCaseMixin):
|
||||||
|
def test_it_returns_404_if_workout_does_not_exist(
|
||||||
|
self,
|
||||||
|
app: Flask,
|
||||||
|
user_1: User,
|
||||||
|
) -> None:
|
||||||
|
client, auth_token = self.get_test_client_and_auth_token(app)
|
||||||
|
|
||||||
|
response = client.get(
|
||||||
|
f'/api/workouts/{get_random_short_id()}/gpx/download',
|
||||||
|
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||||
|
)
|
||||||
|
|
||||||
|
data = json.loads(response.data.decode())
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert 'not found' in data['status']
|
||||||
|
assert 'workout not found' in data['message']
|
||||||
|
|
||||||
|
def test_it_returns_404_if_workout_does_not_have_gpx(
|
||||||
|
self,
|
||||||
|
app: Flask,
|
||||||
|
user_1: User,
|
||||||
|
sport_1_cycling: Sport,
|
||||||
|
workout_cycling_user_1: Workout,
|
||||||
|
) -> None:
|
||||||
|
client, auth_token = self.get_test_client_and_auth_token(app)
|
||||||
|
|
||||||
|
response = client.get(
|
||||||
|
f'/api/workouts/{workout_cycling_user_1.short_id}/gpx/download',
|
||||||
|
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||||
|
)
|
||||||
|
|
||||||
|
data = json.loads(response.data.decode())
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert 'not found' in data['status']
|
||||||
|
assert 'no gpx file for workout' in data['message']
|
||||||
|
|
||||||
|
def test_it_returns_404_if_workout_belongs_to_a_different_user(
|
||||||
|
self,
|
||||||
|
app: Flask,
|
||||||
|
user_1: User,
|
||||||
|
user_2: User,
|
||||||
|
sport_1_cycling: Sport,
|
||||||
|
workout_cycling_user_2: Workout,
|
||||||
|
) -> None:
|
||||||
|
client, auth_token = self.get_test_client_and_auth_token(app)
|
||||||
|
|
||||||
|
response = client.get(
|
||||||
|
f'/api/workouts/{workout_cycling_user_2.short_id}/gpx/download',
|
||||||
|
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||||
|
)
|
||||||
|
|
||||||
|
data = json.loads(response.data.decode())
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert 'not found' in data['status']
|
||||||
|
assert 'workout not found' in data['message']
|
||||||
|
|
||||||
|
def test_it_calls_send_from_directory_if_workout_has_gpx(
|
||||||
|
self,
|
||||||
|
app: Flask,
|
||||||
|
user_1: User,
|
||||||
|
sport_1_cycling: Sport,
|
||||||
|
workout_cycling_user_1: Workout,
|
||||||
|
) -> None:
|
||||||
|
gpx_file_path = 'file.gpx'
|
||||||
|
workout_cycling_user_1.gpx = gpx_file_path
|
||||||
|
with patch('fittrackee.workouts.workouts.send_from_directory') as mock:
|
||||||
|
mock.return_value = 'file'
|
||||||
|
client, auth_token = self.get_test_client_and_auth_token(app)
|
||||||
|
|
||||||
|
client.get(
|
||||||
|
(
|
||||||
|
f'/api/workouts/{workout_cycling_user_1.short_id}/'
|
||||||
|
'gpx/download'
|
||||||
|
),
|
||||||
|
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||||
|
)
|
||||||
|
|
||||||
|
mock.assert_called_once_with(
|
||||||
|
app.config['UPLOAD_FOLDER'],
|
||||||
|
gpx_file_path,
|
||||||
|
mimetype='application/gpx+xml',
|
||||||
|
as_attachment=True,
|
||||||
|
)
|
||||||
|
@ -5,7 +5,14 @@ from datetime import timedelta
|
|||||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from flask import Blueprint, Response, current_app, request, send_file
|
from flask import (
|
||||||
|
Blueprint,
|
||||||
|
Response,
|
||||||
|
current_app,
|
||||||
|
request,
|
||||||
|
send_file,
|
||||||
|
send_from_directory,
|
||||||
|
)
|
||||||
from sqlalchemy import exc
|
from sqlalchemy import exc
|
||||||
from werkzeug.exceptions import RequestEntityTooLarge
|
from werkzeug.exceptions import RequestEntityTooLarge
|
||||||
|
|
||||||
@ -703,6 +710,65 @@ def get_segment_chart_data(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@workouts_blueprint.route(
|
||||||
|
'/workouts/<string:workout_short_id>/gpx/download', methods=['GET']
|
||||||
|
)
|
||||||
|
@authenticate
|
||||||
|
def download_workout_gpx(
|
||||||
|
auth_user_id: int, workout_short_id: str
|
||||||
|
) -> Union[HttpResponse, Response]:
|
||||||
|
"""
|
||||||
|
Download gpx file
|
||||||
|
|
||||||
|
**Example request**:
|
||||||
|
|
||||||
|
.. sourcecode:: http
|
||||||
|
|
||||||
|
GET /api/workouts/kjxavSTUrJvoAh2wvCeGEF/gpx/download HTTP/1.1
|
||||||
|
|
||||||
|
**Example response**:
|
||||||
|
|
||||||
|
.. sourcecode:: http
|
||||||
|
|
||||||
|
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
|
||||||
|
:statuscode 401:
|
||||||
|
- provide a valid auth token
|
||||||
|
- signature expired, please log in again
|
||||||
|
- invalid token, please log in again
|
||||||
|
:statuscode 404:
|
||||||
|
- workout not found
|
||||||
|
- no gpx file for workout
|
||||||
|
"""
|
||||||
|
workout_uuid = decode_short_id(workout_short_id)
|
||||||
|
workout = Workout.query.filter_by(
|
||||||
|
uuid=workout_uuid, user_id=auth_user_id
|
||||||
|
).first()
|
||||||
|
if not workout:
|
||||||
|
return DataNotFoundErrorResponse(
|
||||||
|
data_type='workout',
|
||||||
|
message=f'workout not found (id: {workout_short_id})',
|
||||||
|
)
|
||||||
|
|
||||||
|
if workout.gpx is None:
|
||||||
|
return DataNotFoundErrorResponse(
|
||||||
|
data_type='gpx',
|
||||||
|
message=f'no gpx file for workout (id: {workout_short_id})',
|
||||||
|
)
|
||||||
|
|
||||||
|
return send_from_directory(
|
||||||
|
current_app.config['UPLOAD_FOLDER'],
|
||||||
|
workout.gpx,
|
||||||
|
mimetype='application/gpx+xml',
|
||||||
|
as_attachment=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@workouts_blueprint.route('/workouts/map/<map_id>', methods=['GET'])
|
@workouts_blueprint.route('/workouts/map/<map_id>', methods=['GET'])
|
||||||
def get_map(map_id: int) -> Any:
|
def get_map(map_id: int) -> Any:
|
||||||
"""
|
"""
|
||||||
|
Loading…
Reference in New Issue
Block a user