API - get sports with authenticated user preferences
This commit is contained in:
parent
8237345edd
commit
c05aba92a9
@ -147,34 +147,52 @@
|
||||
<span class="nt">"data"</span><span class="p">:</span> <span class="p">{</span>
|
||||
<span class="nt">"sports"</span><span class="p">:</span> <span class="p">[</span>
|
||||
<span class="p">{</span>
|
||||
<span class="nt">"color"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
||||
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
|
||||
<span class="nt">"is_active"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Cycling (Sport)"</span>
|
||||
<span class="nt">"is_active_for_user"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Cycling (Sport)"</span><span class="p">,</span>
|
||||
<span class="nt">"stopped_speed_threshold"</span><span class="p">:</span> <span class="mi">1</span>
|
||||
<span class="p">},</span>
|
||||
<span class="p">{</span>
|
||||
<span class="nt">"color"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
||||
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
|
||||
<span class="nt">"is_active"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Cycling (Transport)"</span>
|
||||
<span class="nt">"is_active_for_user"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Cycling (Transport)"</span><span class="p">,</span>
|
||||
<span class="nt">"stopped_speed_threshold"</span><span class="p">:</span> <span class="mi">1</span>
|
||||
<span class="p">},</span>
|
||||
<span class="p">{</span>
|
||||
<span class="nt">"color"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
||||
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
|
||||
<span class="nt">"is_active"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Hiking"</span>
|
||||
<span class="nt">"is_active_for_user"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Hiking"</span><span class="p">,</span>
|
||||
<span class="nt">"stopped_speed_threshold"</span><span class="p">:</span> <span class="mf">0.1</span>
|
||||
<span class="p">},</span>
|
||||
<span class="p">{</span>
|
||||
<span class="nt">"color"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
||||
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">4</span><span class="p">,</span>
|
||||
<span class="nt">"is_active"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Mountain Biking"</span>
|
||||
<span class="nt">"is_active_for_user"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Mountain Biking"</span><span class="p">,</span>
|
||||
<span class="nt">"stopped_speed_threshold"</span><span class="p">:</span> <span class="mi">1</span>
|
||||
<span class="p">},</span>
|
||||
<span class="p">{</span>
|
||||
<span class="nt">"color"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
||||
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">5</span><span class="p">,</span>
|
||||
<span class="nt">"is_active"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Running"</span>
|
||||
<span class="nt">"is_active_for_user"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Running"</span><span class="p">,</span>
|
||||
<span class="nt">"stopped_speed_threshold"</span><span class="p">:</span> <span class="mf">0.1</span>
|
||||
<span class="p">},</span>
|
||||
<span class="p">{</span>
|
||||
<span class="nt">"color"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
||||
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">6</span><span class="p">,</span>
|
||||
<span class="nt">"is_active"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Walking"</span>
|
||||
<span class="nt">"is_active_for_user"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Walking"</span><span class="p">,</span>
|
||||
<span class="nt">"stopped_speed_threshold"</span><span class="p">:</span> <span class="mf">0.1</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">]</span>
|
||||
<span class="p">},</span>
|
||||
@ -192,40 +210,58 @@
|
||||
<span class="nt">"data"</span><span class="p">:</span> <span class="p">{</span>
|
||||
<span class="nt">"sports"</span><span class="p">:</span> <span class="p">[</span>
|
||||
<span class="p">{</span>
|
||||
<span class="nt">"color"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
||||
<span class="nt">"has_workouts"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
|
||||
<span class="nt">"is_active"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Cycling (Sport)"</span>
|
||||
<span class="nt">"is_active_for_user"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Cycling (Sport)"</span><span class="p">,</span>
|
||||
<span class="nt">"stopped_speed_threshold"</span><span class="p">:</span> <span class="mi">1</span>
|
||||
<span class="p">},</span>
|
||||
<span class="p">{</span>
|
||||
<span class="nt">"color"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
||||
<span class="nt">"has_workouts"</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
|
||||
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
|
||||
<span class="nt">"is_active"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Cycling (Transport)"</span>
|
||||
<span class="nt">"is_active_for_user"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Cycling (Transport)"</span><span class="p">,</span>
|
||||
<span class="nt">"stopped_speed_threshold"</span><span class="p">:</span> <span class="mi">1</span>
|
||||
<span class="p">},</span>
|
||||
<span class="p">{</span>
|
||||
<span class="nt">"color"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
||||
<span class="nt">"has_workouts"</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
|
||||
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
|
||||
<span class="nt">"is_active"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Hiking"</span>
|
||||
<span class="nt">"is_active_for_user"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Hiking"</span><span class="p">,</span>
|
||||
<span class="nt">"stopped_speed_threshold"</span><span class="p">:</span> <span class="mf">0.1</span>
|
||||
<span class="p">},</span>
|
||||
<span class="p">{</span>
|
||||
<span class="nt">"color"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
||||
<span class="nt">"has_workouts"</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
|
||||
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">4</span><span class="p">,</span>
|
||||
<span class="nt">"is_active"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Mountain Biking"</span>
|
||||
<span class="nt">"is_active_for_user"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Mountain Biking"</span><span class="p">,</span>
|
||||
<span class="nt">"stopped_speed_threshold"</span><span class="p">:</span> <span class="mi">1</span>
|
||||
<span class="p">},</span>
|
||||
<span class="p">{</span>
|
||||
<span class="nt">"color"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
||||
<span class="nt">"has_workouts"</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
|
||||
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">5</span><span class="p">,</span>
|
||||
<span class="nt">"is_active"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Running"</span>
|
||||
<span class="nt">"is_active_for_user"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Running"</span><span class="p">,</span>
|
||||
<span class="nt">"stopped_speed_threshold"</span><span class="p">:</span> <span class="mf">0.1</span>
|
||||
<span class="p">},</span>
|
||||
<span class="p">{</span>
|
||||
<span class="nt">"color"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
||||
<span class="nt">"has_workouts"</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
|
||||
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">6</span><span class="p">,</span>
|
||||
<span class="nt">"is_active"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Walking"</span>
|
||||
<span class="nt">"is_active_for_user"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Walking"</span><span class="p">,</span>
|
||||
<span class="nt">"stopped_speed_threshold"</span><span class="p">:</span> <span class="mf">0.1</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">]</span>
|
||||
<span class="p">},</span>
|
||||
@ -278,9 +314,12 @@
|
||||
<span class="nt">"data"</span><span class="p">:</span> <span class="p">{</span>
|
||||
<span class="nt">"sports"</span><span class="p">:</span> <span class="p">[</span>
|
||||
<span class="p">{</span>
|
||||
<span class="nt">"color"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
||||
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
|
||||
<span class="nt">"is_active"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Cycling (Sport)"</span>
|
||||
<span class="nt">"is_active_for_user"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Cycling (Sport)"</span><span class="p">,</span>
|
||||
<span class="nt">"stopped_speed_threshold"</span><span class="p">:</span> <span class="mi">1</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">]</span>
|
||||
<span class="p">},</span>
|
||||
@ -298,10 +337,13 @@
|
||||
<span class="nt">"data"</span><span class="p">:</span> <span class="p">{</span>
|
||||
<span class="nt">"sports"</span><span class="p">:</span> <span class="p">[</span>
|
||||
<span class="p">{</span>
|
||||
<span class="nt">"color"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
||||
<span class="nt">"has_workouts"</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
|
||||
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
|
||||
<span class="nt">"is_active"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Cycling (Sport)"</span>
|
||||
<span class="nt">"is_active_for_user"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Cycling (Sport)"</span><span class="p">,</span>
|
||||
<span class="nt">"stopped_speed_threshold"</span><span class="p">:</span> <span class="mi">1</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">]</span>
|
||||
<span class="p">},</span>
|
||||
@ -371,10 +413,13 @@ Authenticated user must be an admin</p>
|
||||
<span class="nt">"data"</span><span class="p">:</span> <span class="p">{</span>
|
||||
<span class="nt">"sports"</span><span class="p">:</span> <span class="p">[</span>
|
||||
<span class="p">{</span>
|
||||
<span class="nt">"color"</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
|
||||
<span class="nt">"has_workouts"</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
|
||||
<span class="nt">"id"</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
|
||||
<span class="nt">"is_active"</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Cycling (Sport)"</span>
|
||||
<span class="nt">"is_active_for_user"</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
|
||||
<span class="nt">"label"</span><span class="p">:</span> <span class="s2">"Cycling (Sport)"</span><span class="p">,</span>
|
||||
<span class="nt">"stopped_speed_threshold"</span><span class="p">:</span> <span class="mi">1</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">]</span>
|
||||
<span class="p">},</span>
|
||||
|
File diff suppressed because one or more lines are too long
14
fittrackee/tests/fixtures/fixtures_users.py
vendored
14
fittrackee/tests/fixtures/fixtures_users.py
vendored
@ -96,3 +96,17 @@ def user_sport_1_preference(
|
||||
db.session.add(user_sport)
|
||||
db.session.commit()
|
||||
return user_sport
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def user_admin_sport_1_preference(
|
||||
user_1_admin: User, sport_1_cycling: Sport
|
||||
) -> UserSportPreference:
|
||||
user_sport = UserSportPreference(
|
||||
user_id=user_1_admin.id,
|
||||
sport_id=sport_1_cycling.id,
|
||||
stopped_speed_threshold=sport_1_cycling.stopped_speed_threshold,
|
||||
)
|
||||
db.session.add(user_sport)
|
||||
db.session.commit()
|
||||
return user_sport
|
||||
|
@ -2,7 +2,8 @@ import json
|
||||
|
||||
from flask import Flask
|
||||
|
||||
from fittrackee.users.models import User
|
||||
from fittrackee import db
|
||||
from fittrackee.users.models import User, UserSportPreference
|
||||
from fittrackee.workouts.models import Sport, Workout
|
||||
|
||||
from ..api_test_case import ApiTestCaseMixin
|
||||
@ -11,6 +12,9 @@ expected_sport_1_cycling_result = {
|
||||
'id': 1,
|
||||
'label': 'Cycling',
|
||||
'is_active': True,
|
||||
'is_active_for_user': True,
|
||||
'color': None,
|
||||
'stopped_speed_threshold': 1,
|
||||
}
|
||||
expected_sport_1_cycling_admin_result = expected_sport_1_cycling_result.copy()
|
||||
expected_sport_1_cycling_admin_result['has_workouts'] = False
|
||||
@ -19,6 +23,9 @@ expected_sport_2_running_result = {
|
||||
'id': 2,
|
||||
'label': 'Running',
|
||||
'is_active': True,
|
||||
'is_active_for_user': True,
|
||||
'color': None,
|
||||
'stopped_speed_threshold': 0.1,
|
||||
}
|
||||
expected_sport_2_running_admin_result = expected_sport_2_running_result.copy()
|
||||
expected_sport_2_running_admin_result['has_workouts'] = False
|
||||
@ -27,6 +34,9 @@ expected_sport_1_cycling_inactive_result = {
|
||||
'id': 1,
|
||||
'label': 'Cycling',
|
||||
'is_active': False,
|
||||
'is_active_for_user': False,
|
||||
'color': None,
|
||||
'stopped_speed_threshold': 1,
|
||||
}
|
||||
expected_sport_1_cycling_inactive_admin_result = (
|
||||
expected_sport_1_cycling_inactive_result.copy()
|
||||
@ -108,6 +118,39 @@ class TestGetSports(ApiTestCaseMixin):
|
||||
data['data']['sports'][1] == expected_sport_2_running_admin_result
|
||||
)
|
||||
|
||||
def test_it_gets_sports_with_auth_user_preferences(
|
||||
self,
|
||||
app: Flask,
|
||||
user_1_admin: User,
|
||||
sport_1_cycling: Sport,
|
||||
sport_2_running: Sport,
|
||||
user_admin_sport_1_preference: UserSportPreference,
|
||||
) -> None:
|
||||
user_admin_sport_1_preference.color = '#000000'
|
||||
user_admin_sport_1_preference.stopped_speed_threshold = 0.5
|
||||
user_admin_sport_1_preference.is_active = False
|
||||
db.session.commit()
|
||||
|
||||
client, auth_token = self.get_test_client_and_auth_token(
|
||||
app, as_admin=True
|
||||
)
|
||||
|
||||
response = client.get(
|
||||
'/api/sports',
|
||||
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||
)
|
||||
|
||||
data = json.loads(response.data.decode())
|
||||
assert response.status_code == 200
|
||||
assert 'success' in data['status']
|
||||
assert len(data['data']['sports']) == 2
|
||||
assert data['data']['sports'][0]['color'] == '#000000'
|
||||
assert data['data']['sports'][0]['stopped_speed_threshold'] == 0.5
|
||||
assert data['data']['sports'][0]['is_active_for_user'] is False
|
||||
assert (
|
||||
data['data']['sports'][1] == expected_sport_2_running_admin_result
|
||||
)
|
||||
|
||||
|
||||
class TestGetSport(ApiTestCaseMixin):
|
||||
def test_it_gets_a_sport(
|
||||
@ -126,6 +169,26 @@ class TestGetSport(ApiTestCaseMixin):
|
||||
assert len(data['data']['sports']) == 1
|
||||
assert data['data']['sports'][0] == expected_sport_1_cycling_result
|
||||
|
||||
def test_it_gets_a_sport_with_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.get(
|
||||
'/api/sports/1',
|
||||
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||
)
|
||||
|
||||
data = json.loads(response.data.decode())
|
||||
assert response.status_code == 200
|
||||
assert 'success' in data['status']
|
||||
assert len(data['data']['sports']) == 1
|
||||
assert data['data']['sports'][0] == expected_sport_1_cycling_result
|
||||
|
||||
def test_it_returns_404_if_sport_does_not_exist(
|
||||
self, app: Flask, user_1: User
|
||||
) -> None:
|
||||
@ -202,6 +265,7 @@ class TestUpdateSport(ApiTestCaseMixin):
|
||||
assert 'success' in data['status']
|
||||
assert len(data['data']['sports']) == 1
|
||||
assert data['data']['sports'][0]['is_active'] is False
|
||||
assert data['data']['sports'][0]['is_active_for_user'] is False
|
||||
assert data['data']['sports'][0]['has_workouts'] is False
|
||||
|
||||
def test_it_enables_a_sport(
|
||||
@ -224,6 +288,7 @@ class TestUpdateSport(ApiTestCaseMixin):
|
||||
assert 'success' in data['status']
|
||||
assert len(data['data']['sports']) == 1
|
||||
assert data['data']['sports'][0]['is_active'] is True
|
||||
assert data['data']['sports'][0]['is_active_for_user'] is True
|
||||
assert data['data']['sports'][0]['has_workouts'] is False
|
||||
|
||||
def test_it_disables_a_sport_with_workouts(
|
||||
@ -249,6 +314,7 @@ class TestUpdateSport(ApiTestCaseMixin):
|
||||
assert 'success' in data['status']
|
||||
assert len(data['data']['sports']) == 1
|
||||
assert data['data']['sports'][0]['is_active'] is False
|
||||
assert data['data']['sports'][0]['is_active_for_user'] is False
|
||||
assert data['data']['sports'][0]['has_workouts'] is True
|
||||
|
||||
def test_it_enables_a_sport_with_workouts(
|
||||
@ -275,8 +341,63 @@ class TestUpdateSport(ApiTestCaseMixin):
|
||||
assert 'success' in data['status']
|
||||
assert len(data['data']['sports']) == 1
|
||||
assert data['data']['sports'][0]['is_active'] is True
|
||||
assert data['data']['sports'][0]['is_active_for_user'] is True
|
||||
assert data['data']['sports'][0]['has_workouts'] is True
|
||||
|
||||
def test_it_disables_a_sport_with_preferences(
|
||||
self,
|
||||
app: Flask,
|
||||
user_1_admin: User,
|
||||
sport_1_cycling: Sport,
|
||||
user_admin_sport_1_preference: UserSportPreference,
|
||||
) -> None:
|
||||
client, auth_token = self.get_test_client_and_auth_token(
|
||||
app, as_admin=True
|
||||
)
|
||||
|
||||
response = client.patch(
|
||||
'/api/sports/1',
|
||||
content_type='application/json',
|
||||
data=json.dumps(dict(is_active=False)),
|
||||
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||
)
|
||||
|
||||
data = json.loads(response.data.decode())
|
||||
assert response.status_code == 200
|
||||
assert 'success' in data['status']
|
||||
assert len(data['data']['sports']) == 1
|
||||
assert data['data']['sports'][0]['is_active'] is False
|
||||
assert data['data']['sports'][0]['is_active_for_user'] is False
|
||||
assert data['data']['sports'][0]['is_active_for_user'] is False
|
||||
assert data['data']['sports'][0]['has_workouts'] is False
|
||||
|
||||
def test_it_enables_a_sport_with_preferences(
|
||||
self,
|
||||
app: Flask,
|
||||
user_1_admin: User,
|
||||
sport_1_cycling: Sport,
|
||||
user_admin_sport_1_preference: UserSportPreference,
|
||||
) -> None:
|
||||
sport_1_cycling.is_active = False
|
||||
client, auth_token = self.get_test_client_and_auth_token(
|
||||
app, as_admin=True
|
||||
)
|
||||
|
||||
response = client.patch(
|
||||
'/api/sports/1',
|
||||
content_type='application/json',
|
||||
data=json.dumps(dict(is_active=True)),
|
||||
headers=dict(Authorization=f'Bearer {auth_token}'),
|
||||
)
|
||||
|
||||
data = json.loads(response.data.decode())
|
||||
assert response.status_code == 200
|
||||
assert 'success' in data['status']
|
||||
assert len(data['data']['sports']) == 1
|
||||
assert data['data']['sports'][0]['is_active'] is True
|
||||
assert data['data']['sports'][0]['is_active_for_user'] is True
|
||||
assert data['data']['sports'][0]['has_workouts'] is False
|
||||
|
||||
def test_returns_error_if_user_has_no_admin_rights(
|
||||
self, app: Flask, user_1: User, sport_1_cycling: Sport
|
||||
) -> None:
|
||||
|
@ -2,7 +2,8 @@ from typing import Dict, Optional
|
||||
|
||||
from flask import Flask
|
||||
|
||||
from fittrackee.users.models import User
|
||||
from fittrackee import db
|
||||
from fittrackee.users.models import User, UserSportPreference
|
||||
from fittrackee.workouts.models import Sport, Workout
|
||||
|
||||
|
||||
@ -15,10 +16,13 @@ class TestSportModel:
|
||||
assert 'Cycling' == sport.label
|
||||
assert '<Sport \'Cycling\'>' == str(sport)
|
||||
|
||||
serialized_sport = sport.serialize(is_admin)
|
||||
serialized_sport = sport.serialize(is_admin=is_admin)
|
||||
assert 1 == serialized_sport['id']
|
||||
assert 'Cycling' == serialized_sport['label']
|
||||
assert serialized_sport['is_active'] is True
|
||||
assert serialized_sport['is_active_for_user'] is True
|
||||
assert serialized_sport['color'] is None
|
||||
assert serialized_sport['stopped_speed_threshold'] == 1
|
||||
return serialized_sport
|
||||
|
||||
def test_sport_model(self, app: Flask, sport_1_cycling: Sport) -> None:
|
||||
@ -44,3 +48,87 @@ class TestSportModel:
|
||||
) -> None:
|
||||
serialized_sport = self.assert_sport_model(sport_1_cycling, True)
|
||||
assert serialized_sport['has_workouts'] is True
|
||||
|
||||
|
||||
class TestSportModelWithPreferences:
|
||||
def test_sport_model_with_color_preference(
|
||||
self,
|
||||
app: Flask,
|
||||
user_1: User,
|
||||
sport_1_cycling: Sport,
|
||||
user_sport_1_preference: UserSportPreference,
|
||||
) -> None:
|
||||
user_sport_1_preference.color = '#00000'
|
||||
|
||||
serialized_sport = sport_1_cycling.serialize(
|
||||
sport_preferences=user_sport_1_preference.serialize()
|
||||
)
|
||||
assert serialized_sport['id'] == 1
|
||||
assert serialized_sport['label'] == 'Cycling'
|
||||
assert serialized_sport['is_active'] is True
|
||||
assert serialized_sport['is_active_for_user'] is True
|
||||
assert serialized_sport['color'] == '#00000'
|
||||
assert serialized_sport['stopped_speed_threshold'] == 1
|
||||
assert 'has_workouts' not in serialized_sport
|
||||
|
||||
def test_sport_model_with_is_active_preference(
|
||||
self,
|
||||
app: Flask,
|
||||
user_1: User,
|
||||
sport_1_cycling: Sport,
|
||||
user_sport_1_preference: UserSportPreference,
|
||||
) -> None:
|
||||
user_sport_1_preference.is_active = False
|
||||
|
||||
serialized_sport = sport_1_cycling.serialize(
|
||||
sport_preferences=user_sport_1_preference.serialize()
|
||||
)
|
||||
assert serialized_sport['id'] == 1
|
||||
assert serialized_sport['label'] == 'Cycling'
|
||||
assert serialized_sport['is_active'] is True
|
||||
assert serialized_sport['is_active_for_user'] is False
|
||||
assert serialized_sport['color'] is None
|
||||
assert serialized_sport['stopped_speed_threshold'] == 1
|
||||
assert 'has_workouts' not in serialized_sport
|
||||
|
||||
def test_inactive_sport_model_with_is_active_preference(
|
||||
self,
|
||||
app: Flask,
|
||||
user_1: User,
|
||||
sport_1_cycling: Sport,
|
||||
user_sport_1_preference: UserSportPreference,
|
||||
) -> None:
|
||||
sport_1_cycling.is_active = False
|
||||
user_sport_1_preference.is_active = True
|
||||
|
||||
serialized_sport = sport_1_cycling.serialize(
|
||||
sport_preferences=user_sport_1_preference.serialize()
|
||||
)
|
||||
assert serialized_sport['id'] == 1
|
||||
assert serialized_sport['label'] == 'Cycling'
|
||||
assert serialized_sport['is_active'] is False
|
||||
assert serialized_sport['is_active_for_user'] is False
|
||||
assert serialized_sport['color'] is None
|
||||
assert serialized_sport['stopped_speed_threshold'] == 1
|
||||
assert 'has_workouts' not in serialized_sport
|
||||
|
||||
def test_sport_model_with_threshold_preference(
|
||||
self,
|
||||
app: Flask,
|
||||
user_1: User,
|
||||
sport_1_cycling: Sport,
|
||||
user_sport_1_preference: UserSportPreference,
|
||||
) -> None:
|
||||
user_sport_1_preference.stopped_speed_threshold = 0.5
|
||||
db.session.commit()
|
||||
|
||||
serialized_sport = sport_1_cycling.serialize(
|
||||
sport_preferences=user_sport_1_preference.serialize()
|
||||
)
|
||||
assert serialized_sport['id'] == 1
|
||||
assert serialized_sport['label'] == 'Cycling'
|
||||
assert serialized_sport['is_active'] is True
|
||||
assert serialized_sport['is_active_for_user'] is True
|
||||
assert serialized_sport['color'] is None
|
||||
assert serialized_sport['stopped_speed_threshold'] == 0.5
|
||||
assert 'has_workouts' not in serialized_sport
|
||||
|
@ -40,11 +40,6 @@ class User(BaseModel):
|
||||
'Record', lazy=True, backref=db.backref('user', lazy='joined')
|
||||
)
|
||||
language = db.Column(db.String(50), nullable=True)
|
||||
sport_preferences = db.relationship(
|
||||
'UserSportPreference',
|
||||
lazy=True,
|
||||
backref=db.backref('user', lazy='joined'),
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'<User {self.username!r}>'
|
||||
|
@ -85,11 +85,30 @@ class Sport(BaseModel):
|
||||
def __init__(self, label: str) -> None:
|
||||
self.label = label
|
||||
|
||||
def serialize(self, is_admin: Optional[bool] = False) -> Dict:
|
||||
def serialize(
|
||||
self,
|
||||
is_admin: Optional[bool] = False,
|
||||
sport_preferences: Optional[Dict] = None,
|
||||
) -> Dict:
|
||||
serialized_sport = {
|
||||
'id': self.id,
|
||||
'label': self.label,
|
||||
'is_active': self.is_active,
|
||||
'is_active_for_user': (
|
||||
self.is_active
|
||||
if sport_preferences is None
|
||||
else (sport_preferences['is_active'] and self.is_active)
|
||||
),
|
||||
'color': (
|
||||
None
|
||||
if sport_preferences is None
|
||||
else sport_preferences['color']
|
||||
),
|
||||
'stopped_speed_threshold': (
|
||||
self.stopped_speed_threshold
|
||||
if sport_preferences is None
|
||||
else sport_preferences['stopped_speed_threshold']
|
||||
),
|
||||
}
|
||||
if is_admin:
|
||||
serialized_sport['has_workouts'] = len(self.workouts) > 0
|
||||
|
@ -11,7 +11,7 @@ from fittrackee.responses import (
|
||||
handle_error_and_return_response,
|
||||
)
|
||||
from fittrackee.users.decorators import authenticate, authenticate_as_admin
|
||||
from fittrackee.users.models import User
|
||||
from fittrackee.users.models import User, UserSportPreference
|
||||
|
||||
from .models import Sport
|
||||
|
||||
@ -44,34 +44,52 @@ def get_sports(auth_user_id: int) -> Dict:
|
||||
"data": {
|
||||
"sports": [
|
||||
{
|
||||
"color": null,
|
||||
"id": 1,
|
||||
"is_active": true,
|
||||
"label": "Cycling (Sport)"
|
||||
"is_active_for_user": true,
|
||||
"label": "Cycling (Sport)",
|
||||
"stopped_speed_threshold": 1
|
||||
},
|
||||
{
|
||||
"color": null,
|
||||
"id": 2,
|
||||
"is_active": true,
|
||||
"label": "Cycling (Transport)"
|
||||
"is_active_for_user": true,
|
||||
"label": "Cycling (Transport)",
|
||||
"stopped_speed_threshold": 1
|
||||
},
|
||||
{
|
||||
"color": null,
|
||||
"id": 3,
|
||||
"is_active": true,
|
||||
"label": "Hiking"
|
||||
"is_active_for_user": true,
|
||||
"label": "Hiking",
|
||||
"stopped_speed_threshold": 0.1
|
||||
},
|
||||
{
|
||||
"color": null,
|
||||
"id": 4,
|
||||
"is_active": true,
|
||||
"label": "Mountain Biking"
|
||||
"is_active_for_user": true,
|
||||
"label": "Mountain Biking",
|
||||
"stopped_speed_threshold": 1
|
||||
},
|
||||
{
|
||||
"color": null,
|
||||
"id": 5,
|
||||
"is_active": true,
|
||||
"label": "Running"
|
||||
"is_active_for_user": true,
|
||||
"label": "Running",
|
||||
"stopped_speed_threshold": 0.1
|
||||
},
|
||||
{
|
||||
"color": null,
|
||||
"id": 6,
|
||||
"is_active": true,
|
||||
"label": "Walking"
|
||||
"is_active_for_user": true,
|
||||
"label": "Walking",
|
||||
"stopped_speed_threshold": 0.1
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -89,40 +107,58 @@ def get_sports(auth_user_id: int) -> Dict:
|
||||
"data": {
|
||||
"sports": [
|
||||
{
|
||||
"color": null,
|
||||
"has_workouts": true,
|
||||
"id": 1,
|
||||
"is_active": true,
|
||||
"label": "Cycling (Sport)"
|
||||
"is_active_for_user": true,
|
||||
"label": "Cycling (Sport)",
|
||||
"stopped_speed_threshold": 1
|
||||
},
|
||||
{
|
||||
"color": null,
|
||||
"has_workouts": false,
|
||||
"id": 2,
|
||||
"is_active": true,
|
||||
"label": "Cycling (Transport)"
|
||||
"is_active_for_user": true,
|
||||
"label": "Cycling (Transport)",
|
||||
"stopped_speed_threshold": 1
|
||||
},
|
||||
{
|
||||
"color": null,
|
||||
"has_workouts": false,
|
||||
"id": 3,
|
||||
"is_active": true,
|
||||
"label": "Hiking"
|
||||
"is_active_for_user": true,
|
||||
"label": "Hiking",
|
||||
"stopped_speed_threshold": 0.1
|
||||
},
|
||||
{
|
||||
"color": null,
|
||||
"has_workouts": false,
|
||||
"id": 4,
|
||||
"is_active": true,
|
||||
"label": "Mountain Biking"
|
||||
"is_active_for_user": true,
|
||||
"label": "Mountain Biking",
|
||||
"stopped_speed_threshold": 1
|
||||
},
|
||||
{
|
||||
"color": null,
|
||||
"has_workouts": false,
|
||||
"id": 5,
|
||||
"is_active": true,
|
||||
"label": "Running"
|
||||
"is_active_for_user": true,
|
||||
"label": "Running",
|
||||
"stopped_speed_threshold": 0.1
|
||||
},
|
||||
{
|
||||
"color": null,
|
||||
"has_workouts": false,
|
||||
"id": 6,
|
||||
"is_active": true,
|
||||
"label": "Walking"
|
||||
"is_active_for_user": true,
|
||||
"label": "Walking",
|
||||
"stopped_speed_threshold": 0.1
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -142,9 +178,22 @@ def get_sports(auth_user_id: int) -> Dict:
|
||||
"""
|
||||
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
|
||||
).first()
|
||||
sports_data.append(
|
||||
sport.serialize(
|
||||
is_admin=user.admin,
|
||||
sport_preferences=sport_preferences.serialize()
|
||||
if sport_preferences
|
||||
else None,
|
||||
)
|
||||
)
|
||||
return {
|
||||
'status': 'success',
|
||||
'data': {'sports': [sport.serialize(user.admin) for sport in sports]},
|
||||
'data': {'sports': sports_data},
|
||||
}
|
||||
|
||||
|
||||
@ -174,9 +223,12 @@ def get_sport(auth_user_id: int, sport_id: int) -> Union[Dict, HttpResponse]:
|
||||
"data": {
|
||||
"sports": [
|
||||
{
|
||||
"color": null,
|
||||
"id": 1,
|
||||
"is_active": true,
|
||||
"label": "Cycling (Sport)"
|
||||
"is_active_for_user": true,
|
||||
"label": "Cycling (Sport)",
|
||||
"stopped_speed_threshold": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -194,10 +246,13 @@ def get_sport(auth_user_id: int, sport_id: int) -> Union[Dict, HttpResponse]:
|
||||
"data": {
|
||||
"sports": [
|
||||
{
|
||||
"color": null,
|
||||
"has_workouts": false,
|
||||
"id": 1,
|
||||
"is_active": true,
|
||||
"label": "Cycling (Sport)"
|
||||
"is_active_for_user": true,
|
||||
"label": "Cycling (Sport)",
|
||||
"stopped_speed_threshold": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -234,9 +289,21 @@ def get_sport(auth_user_id: int, sport_id: int) -> Union[Dict, HttpResponse]:
|
||||
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
|
||||
).first()
|
||||
return {
|
||||
'status': 'success',
|
||||
'data': {'sports': [sport.serialize(user.admin)]},
|
||||
'data': {
|
||||
'sports': [
|
||||
sport.serialize(
|
||||
is_admin=user.admin,
|
||||
sport_preferences=sport_preferences.serialize()
|
||||
if sport_preferences
|
||||
else None,
|
||||
)
|
||||
]
|
||||
},
|
||||
}
|
||||
return DataNotFoundErrorResponse('sports')
|
||||
|
||||
@ -270,10 +337,13 @@ def update_sport(
|
||||
"data": {
|
||||
"sports": [
|
||||
{
|
||||
"color": null,
|
||||
"has_workouts": false,
|
||||
"id": 1,
|
||||
"is_active": false,
|
||||
"label": "Cycling (Sport)"
|
||||
"is_active_for_user": false,
|
||||
"label": "Cycling (Sport)",
|
||||
"stopped_speed_threshold": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -317,15 +387,28 @@ 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')
|
||||
|
||||
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
|
||||
).first()
|
||||
return {
|
||||
'status': 'success',
|
||||
'data': {'sports': [sport.serialize(True)]},
|
||||
'data': {
|
||||
'sports': [
|
||||
sport.serialize(
|
||||
is_admin=user.admin,
|
||||
sport_preferences=sport_preferences.serialize()
|
||||
if sport_preferences
|
||||
else None,
|
||||
)
|
||||
]
|
||||
},
|
||||
}
|
||||
|
||||
except (exc.IntegrityError, exc.OperationalError, ValueError) as e:
|
||||
|
Loading…
Reference in New Issue
Block a user