API - add elevation to workout w/o gpx file when provided
This commit is contained in:
parent
fbda86e123
commit
8a0e1d2b40
@ -886,6 +886,49 @@ class TestPostWorkoutWithoutGpx(ApiTestCaseMixin):
|
|||||||
assert len(data['data']['workouts']) == 1
|
assert len(data['data']['workouts']) == 1
|
||||||
assert_workout_data_wo_gpx(data)
|
assert_workout_data_wo_gpx(data)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'input_ascent, input_descent',
|
||||||
|
[
|
||||||
|
(100, 150),
|
||||||
|
(0, 150),
|
||||||
|
(100, 0),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_it_adds_workout_with_ascent_and_descent_when_provided(
|
||||||
|
self,
|
||||||
|
app: Flask,
|
||||||
|
user_1: User,
|
||||||
|
sport_1_cycling: Sport,
|
||||||
|
input_ascent: int,
|
||||||
|
input_descent: int,
|
||||||
|
) -> None:
|
||||||
|
client, auth_token = self.get_test_client_and_auth_token(
|
||||||
|
app, user_1.email
|
||||||
|
)
|
||||||
|
|
||||||
|
response = client.post(
|
||||||
|
'/api/workouts/no_gpx',
|
||||||
|
content_type='application/json',
|
||||||
|
data=json.dumps(
|
||||||
|
dict(
|
||||||
|
sport_id=1,
|
||||||
|
duration=3600,
|
||||||
|
workout_date='2018-05-15 14:05',
|
||||||
|
distance=10,
|
||||||
|
ascent=input_ascent,
|
||||||
|
descent=input_descent,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||||
|
)
|
||||||
|
|
||||||
|
data = json.loads(response.data.decode())
|
||||||
|
assert response.status_code == 201
|
||||||
|
assert 'created' in data['status']
|
||||||
|
assert len(data['data']['workouts']) == 1
|
||||||
|
assert data['data']['workouts'][0]['ascent'] == input_ascent
|
||||||
|
assert data['data']['workouts'][0]['descent'] == input_descent
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'description,input_data',
|
'description,input_data',
|
||||||
[
|
[
|
||||||
@ -940,6 +983,82 @@ class TestPostWorkoutWithoutGpx(ApiTestCaseMixin):
|
|||||||
|
|
||||||
self.assert_400(response)
|
self.assert_400(response)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'description,input_data',
|
||||||
|
[
|
||||||
|
("only ascent", {"ascent": 100}),
|
||||||
|
("only descent", {"descent": 150}),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_it_returns_400_when_ascent_or_descent_are_missing(
|
||||||
|
self,
|
||||||
|
app: Flask,
|
||||||
|
user_1: User,
|
||||||
|
sport_1_cycling: Sport,
|
||||||
|
description: str,
|
||||||
|
input_data: Dict,
|
||||||
|
) -> None:
|
||||||
|
client, auth_token = self.get_test_client_and_auth_token(
|
||||||
|
app, user_1.email
|
||||||
|
)
|
||||||
|
|
||||||
|
response = client.post(
|
||||||
|
'/api/workouts/no_gpx',
|
||||||
|
content_type='application/json',
|
||||||
|
data=json.dumps(
|
||||||
|
{
|
||||||
|
'sport_id': 1,
|
||||||
|
'duration': 3600,
|
||||||
|
'workout_date': '2018-05-15 14:05',
|
||||||
|
'distance': 10,
|
||||||
|
**input_data,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assert_400(response)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'description,input_data',
|
||||||
|
[
|
||||||
|
("ascent is below 0", {"ascent": -100, "descent": 100}),
|
||||||
|
("descent is below 0", {"ascent": 150, "descent": -100}),
|
||||||
|
("ascent is None", {"ascent": None, "descent": 100}),
|
||||||
|
("descent is None", {"ascent": 150, "descent": None}),
|
||||||
|
("ascent is invalid", {"ascent": "a", "descent": 100}),
|
||||||
|
("descent is invalid", {"ascent": 150, "descent": "b"}),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_it_returns_400_when_ascent_or_descent_are_invalid(
|
||||||
|
self,
|
||||||
|
app: Flask,
|
||||||
|
user_1: User,
|
||||||
|
sport_1_cycling: Sport,
|
||||||
|
description: str,
|
||||||
|
input_data: Dict,
|
||||||
|
) -> None:
|
||||||
|
client, auth_token = self.get_test_client_and_auth_token(
|
||||||
|
app, user_1.email
|
||||||
|
)
|
||||||
|
|
||||||
|
response = client.post(
|
||||||
|
'/api/workouts/no_gpx',
|
||||||
|
content_type='application/json',
|
||||||
|
data=json.dumps(
|
||||||
|
{
|
||||||
|
'sport_id': 1,
|
||||||
|
'duration': 3600,
|
||||||
|
'workout_date': '2018-05-15 14:05',
|
||||||
|
'distance': 10,
|
||||||
|
**input_data,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assert_400(response)
|
||||||
|
|
||||||
def test_it_returns_500_if_workout_date_format_is_invalid(
|
def test_it_returns_500_if_workout_date_format_is_invalid(
|
||||||
self, app: Flask, user_1: User, sport_1_cycling: Sport
|
self, app: Flask, user_1: User, sport_1_cycling: Sport
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -75,6 +75,48 @@ class TestWorkoutModel:
|
|||||||
assert serialized_workout['with_gpx'] is False
|
assert serialized_workout['with_gpx'] is False
|
||||||
assert str(serialized_workout['workout_date']) == '2018-01-01 00:00:00'
|
assert str(serialized_workout['workout_date']) == '2018-01-01 00:00:00'
|
||||||
|
|
||||||
|
def test_serialize_for_workout_without_gpx_and_with_elevation(
|
||||||
|
self,
|
||||||
|
app: Flask,
|
||||||
|
sport_1_cycling: Sport,
|
||||||
|
user_1: User,
|
||||||
|
workout_cycling_user_1: Workout,
|
||||||
|
) -> None:
|
||||||
|
workout = workout_cycling_user_1
|
||||||
|
workout.ascent = 0
|
||||||
|
workout.descent = 10
|
||||||
|
|
||||||
|
serialized_workout = workout.serialize()
|
||||||
|
assert serialized_workout['ascent'] == workout.ascent
|
||||||
|
assert serialized_workout['ave_speed'] == float(workout.ave_speed)
|
||||||
|
assert serialized_workout['bounds'] == []
|
||||||
|
assert 'creation_date' in serialized_workout
|
||||||
|
assert serialized_workout['descent'] == workout.descent
|
||||||
|
assert serialized_workout['distance'] == float(workout.distance)
|
||||||
|
assert serialized_workout['duration'] == str(workout.duration)
|
||||||
|
assert serialized_workout['id'] == workout.short_id
|
||||||
|
assert serialized_workout['map'] is None
|
||||||
|
assert serialized_workout['max_alt'] is None
|
||||||
|
assert serialized_workout['max_speed'] == float(workout.max_speed)
|
||||||
|
assert serialized_workout['min_alt'] is None
|
||||||
|
assert serialized_workout['modification_date'] is not None
|
||||||
|
assert serialized_workout['moving'] == str(workout.moving)
|
||||||
|
assert serialized_workout['next_workout'] is None
|
||||||
|
assert serialized_workout['notes'] is None
|
||||||
|
assert serialized_workout['pauses'] is None
|
||||||
|
assert serialized_workout['previous_workout'] is None
|
||||||
|
assert serialized_workout['records'] == [
|
||||||
|
record.serialize() for record in workout.records
|
||||||
|
]
|
||||||
|
assert serialized_workout['segments'] == []
|
||||||
|
assert serialized_workout['sport_id'] == workout.sport_id
|
||||||
|
assert serialized_workout['title'] == workout.title
|
||||||
|
assert serialized_workout['user'] == workout.user.username
|
||||||
|
assert serialized_workout['weather_end'] is None
|
||||||
|
assert serialized_workout['weather_start'] is None
|
||||||
|
assert serialized_workout['with_gpx'] is False
|
||||||
|
assert str(serialized_workout['workout_date']) == '2018-01-01 00:00:00'
|
||||||
|
|
||||||
def test_serialize_for_workout_with_gpx(
|
def test_serialize_for_workout_with_gpx(
|
||||||
self,
|
self,
|
||||||
app: Flask,
|
app: Flask,
|
||||||
|
@ -296,8 +296,10 @@ class Workout(BaseModel):
|
|||||||
'distance': float(self.distance) if self.distance else None,
|
'distance': float(self.distance) if self.distance else None,
|
||||||
'min_alt': float(self.min_alt) if self.min_alt else None,
|
'min_alt': float(self.min_alt) if self.min_alt else None,
|
||||||
'max_alt': float(self.max_alt) if self.max_alt else None,
|
'max_alt': float(self.max_alt) if self.max_alt else None,
|
||||||
'descent': float(self.descent) if self.descent else None,
|
'descent': float(self.descent)
|
||||||
'ascent': float(self.ascent) if self.ascent else None,
|
if self.descent is not None
|
||||||
|
else None,
|
||||||
|
'ascent': float(self.ascent) if self.ascent is not None else None,
|
||||||
'max_speed': float(self.max_speed) if self.max_speed else None,
|
'max_speed': float(self.max_speed) if self.max_speed else None,
|
||||||
'ave_speed': float(self.ave_speed) if self.ave_speed else None,
|
'ave_speed': float(self.ave_speed) if self.ave_speed else None,
|
||||||
'with_gpx': self.gpx is not None,
|
'with_gpx': self.gpx is not None,
|
||||||
|
@ -160,6 +160,8 @@ def create_workout(
|
|||||||
else float(new_workout.distance) / (duration.seconds / 3600)
|
else float(new_workout.distance) / (duration.seconds / 3600)
|
||||||
)
|
)
|
||||||
new_workout.max_speed = new_workout.ave_speed
|
new_workout.max_speed = new_workout.ave_speed
|
||||||
|
new_workout.ascent = workout_data.get('ascent')
|
||||||
|
new_workout.descent = workout_data.get('descent')
|
||||||
return new_workout
|
return new_workout
|
||||||
|
|
||||||
|
|
||||||
|
@ -1132,13 +1132,15 @@ def post_workout_no_gpx(
|
|||||||
"status": "success"
|
"status": "success"
|
||||||
}
|
}
|
||||||
|
|
||||||
:<json string workout_date: workout date, in user timezone
|
:<json float ascent: workout ascent (not mandatory)
|
||||||
(format: ``%Y-%m-%d %H:%M``)
|
:<json float descent: workout descent (not mandatory)
|
||||||
:<json float distance: workout distance in km
|
:<json float distance: workout distance in km
|
||||||
:<json integer duration: workout duration in seconds
|
:<json integer duration: workout duration in seconds
|
||||||
:<json string notes: notes (not mandatory)
|
:<json string notes: notes (not mandatory)
|
||||||
:<json integer sport_id: workout sport id
|
:<json integer sport_id: workout sport id
|
||||||
:<json string title: workout title
|
:<json string title: workout title (not mandatory)
|
||||||
|
:<json string workout_date: workout date, in user timezone
|
||||||
|
(format: ``%Y-%m-%d %H:%M``)
|
||||||
|
|
||||||
:reqheader Authorization: OAuth 2.0 Bearer Token
|
:reqheader Authorization: OAuth 2.0 Bearer Token
|
||||||
|
|
||||||
@ -1161,6 +1163,20 @@ def post_workout_no_gpx(
|
|||||||
):
|
):
|
||||||
return InvalidPayloadErrorResponse()
|
return InvalidPayloadErrorResponse()
|
||||||
|
|
||||||
|
ascent = workout_data.get('ascent')
|
||||||
|
descent = workout_data.get('descent')
|
||||||
|
try:
|
||||||
|
if (
|
||||||
|
(ascent is None and descent is not None)
|
||||||
|
or (ascent is not None and descent is None)
|
||||||
|
or (
|
||||||
|
(ascent is not None and descent is not None)
|
||||||
|
and (float(ascent) < 0 or float(descent) < 0)
|
||||||
|
)
|
||||||
|
):
|
||||||
|
return InvalidPayloadErrorResponse()
|
||||||
|
except ValueError:
|
||||||
|
return InvalidPayloadErrorResponse()
|
||||||
try:
|
try:
|
||||||
new_workout = create_workout(auth_user, workout_data)
|
new_workout = create_workout(auth_user, workout_data)
|
||||||
db.session.add(new_workout)
|
db.session.add(new_workout)
|
||||||
|
Loading…
Reference in New Issue
Block a user